Idiomatic Type Conversion in Go
Asked Answered
G

3

10

I was playing around with Go and was wondering what the best way is to perform idiomatic type conversions in Go. Basically my problem lays within automatic type conversions between uint8, uint64, and float64. From my experience with other languages a multiplication of a uint8 with a uint64 will yield a uint64 value, but not so in go.

Here is an example that I build and I ask if this is the idiomatic way of writing this code or if I'm missing an important language construct.

package main

import ("math";"fmt")

const(Width=64)

func main() {

    var index uint32
    var bits uint8

    index = 100
    bits = 3

    var c uint64
    // This is the line of interest vvvv
    c = uint64(math.Ceil(float64(index * uint32(bits))/float64(Width)))
    fmt.Println("Test: %v\n", c)
}

From my point of view the calculation of the ceiling value seems unnecessary complex because of all the explicit type conversions.

Thanks!

Gwenni answered 13/11, 2012 at 20:10 Comment(4)
Why the floating point math? play.golang.org/p/kdV9vnIqPNWarrantee
Imagine you have a two 64 bits wide blocks storing 8 bit integers and you want to store 9 elements and need to know how many blocks to allocate without overhead. 9*8/64 = 1, but 8*8/64=1 as well. Maybe I'm missing an interesting +/- 1 thing here...Gwenni
Use: (9*8+(64-1))/64 = 2 and (8*8+(64-1))/64 = 1. See my answer.Mol
float64(b[0]) to set an uint8/byte to a float64. See https://mcmap.net/q/56302/-how-to-convert-uint8-to-string. byte(f) to set a float64 to an uint8/byte. See https://mcmap.net/q/56303/-how-to-round-to-nearest-int-when-casting-float-to-int-in-go.Respond
D
7

There are no implicit type conversions for non-constant values.

You can write

var x float64
x = 1

But you cannot write

var x float64
var y int

y = 1
x = y

See the spec for reference.

There's a good reason, to not allow automatic/implicit type conversions, as they can become very messy and one has to learn many rules to circumvent the various caveats that may occur. Take the Integer Conversion Rules in C for example.

Denticulation answered 13/11, 2012 at 20:41 Comment(0)
M
1

For example,

package main

import "fmt"

func CeilUint(a, b uint64) uint64 {
    return (a + (b - 1)) / b
}

func main() {
    const Width = 64
    var index uint32 = 100
    var bits uint8 = 3
    var c uint64 = CeilUint(uint64(index)*uint64(bits), Width)
    fmt.Println("Test:", c)
}

Output:

Test: 5
Mol answered 14/11, 2012 at 13:7 Comment(1)
Even though it's correct in it's own way. The other answer was the one I'm looking for. ThanksGwenni
R
1

To add to @nemo terrific answer. The convenience of automatic conversion between numeric types in C is outweighed by the confusion it causes. See https://Golang.org/doc/faq#conversions. Thats why you can't even convert from int to int32 implicitly. See https://mcmap.net/q/56304/-casting-between-number-types-in-golang.

package main

import (
    . "fmt"
    . "strconv"
)

func main() {
    i := 71
    c := []interface{}{byte(i), []byte(string(i)), float64(i), i, rune(i), Itoa(i), i != 0}
    checkType(c)
}

func checkType(s []interface{}) {
    for k, _ := range s {
        Printf("%T %v\n", s[k], s[k])
    }
}

byte(i) creates a uint8 with a value of 71, []byte(string(i)) a []uint8 with [71], float64(i) float64 71, i int 71, rune(i) int32 71, Itoa(i) string 71 and i != 0 a bool with a value of true.

Since Go won't convert numeric types automatically for you (See https://mcmap.net/q/56304/-casting-between-number-types-in-golang) you have to convert between types manually. See https://mcmap.net/q/56304/-casting-between-number-types-in-golang. Note, Itoa(i) sets an "Integer to an ASCII". See comment in https://mcmap.net/q/53864/-how-to-convert-an-int-value-to-string-in-go.

Respond answered 5/7, 2020 at 7:23 Comment(1)

© 2022 - 2024 — McMap. All rights reserved.