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!

grundprinzip
  • 2,471
  • 1
  • 20
  • 34
  • Why the floating point math? http://play.golang.org/p/kdV9vnIqPN – zzzz Nov 13 '12 at 20:53
  • 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... – grundprinzip Nov 13 '12 at 21:13
  • 2
    Use: (9*8+(64-1))/64 = 2 and (8*8+(64-1))/64 = 1. See my answer. – peterSO Nov 14 '12 at 13:17
  • `float64(b[0])` to set an uint8/byte to a float64. See https://stackoverflow.com/a/62725637/12817546. `byte(f)` to set a float64 to an uint8/byte. See https://stackoverflow.com/a/62753031/12817546. –  Jul 10 '20 at 00:18

3 Answers3

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.

nemo
  • 55,207
  • 13
  • 135
  • 135
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
peterSO
  • 158,998
  • 31
  • 281
  • 276
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://stackoverflow.com/a/13852456/12817546.

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://stackoverflow.com/a/13851553/12817546) you have to convert between types manually. See https://stackoverflow.com/a/41419962/12817546. Note, Itoa(i) sets an "Integer to an ASCII". See comment in https://stackoverflow.com/a/10105983/12817546.

  • A boolean, numeric, or string type can be set to another type. For`[]byte` see https://stackoverflow.com/a/62725637/12817546, for `float64` see https://stackoverflow.com/a/62753031/12817546, `int` see https://stackoverflow.com/a/62737936/12817546, `string` see https://stackoverflow.com/a/62740786/12817546 and for `bool` see https://stackoverflow.com/a/62726854/12817546. –  Jul 07 '20 at 09:29