How to convert a slice to alias slice in go? - go

I defined my Int type as int.
I want to convert a slice of Int to a slice of int, but got a compile error:
cannot convert c (type []Int) to type []int
How can I fix this?
package main
import (
"fmt"
)
type Int int
func main() {
var c = []Int{}
var x = []int( c )
fmt.Println(len(x))
}

Your Int type is not an alias of int, it's a new type with int being its underlying type. This type of conversion is not supported / allowed by the language spec. More specifically, converting a slice type to another where the element type is different is not allowed.
The safe way
If you only need an []int "view" of the []Int, the safe way to "convert" would be to create a copy of the []Int slice but with a type of []int, and use a for range loop and convert each individual element from Int to int type:
var c = []Int{1, 2}
x := make([]int, len(c))
for i, v := range c {
x[i] = int(v)
}
fmt.Println(x)
Output (try it on the Go Playground):
[1 2]
The unsafe way
There is also an "unsafe" way:
var c = []Int{1, 2}
var x []int = *(*[]int)(unsafe.Pointer(&c))
fmt.Println(x)
Output is the same. Try this one on the Go Playground.
What happens here is that the address of c (which is &c) is converted to unsafe.Pointer (all pointers can be converted to this), which then is converted to *[]int (unsafe.Pointer can be converted to any pointer type), and then this pointer is dereferenced which gives a value of type []int. In this case it is safe because the memory layout of []Int and []int is identical (because Int has int as its underlying type), but in general, use of package unsafe should be avoided whenever possible.
If Int would be a "true" alias
Note that if Int would be a "true" alias to int, the conversion would not even be needed:
var c = []Int{1, 2}
var x []int = c
fmt.Println(x)
Output is the same as above (try it on the Go Playground). The reason why this works is because writing []Int is identical to writing []int, they are the same type, so you don't even need a conversion here.
By using a slice type
Also note that if you would create a new type with []int as its underlying type, you could use type conversion:
type IntSlice = []int
func main() {
var c = IntSlice{1, 2}
var x []int = []int(c)
fmt.Println(x)
}
Output is again the same. Try this one on the Go Playground.

The problem is that you are not creating Int as an alias, doing
type Int int
Will create Int as a new type that can't interoperate with int.
The proper way to create Int as an alias is
type Int = int
With this change your program is ok.

Technically, type Int int does not define an alias, but a completely new type. Even though Int and int now have identical underlying types and can be converted to each other, that does not apply to slices. More about allowed conversions is in the spec.

Actually, a slice a simply points to an underlying array of the designated type (in this case the types are different, Int and int). So unless your underlying type is the same a conversion won't work. Just to illustrate this something like this would work though:
package main
import (
"fmt"
)
type Int int
type IntSl []int
func main() {
var c = IntSl{2, 3, 4}
var x []int
x = []int(c)
var a Int
var b int
a = 1
b = int(a)
fmt.Println(len(x), a, b, c)
}
Playground : https://play.golang.org/p/ROOX1XoXg1j
As #icza points out there's the unsafe way & of course you can always do the conversion looping over each of the elements which could be expensive.

Related

Go: How to convert a float32 pointer to float64 pointer

How do you convert a float32 pointer *float32 to a float64 pointer *float64.
package main
import "fmt"
func main() {
var value *float32
v := float64(*value)
vp := &v
fmt.Println(vp)
}
The following code returns
runtime error: invalid memory address or nil pointer dereference
The reason your code is failing is simply that you are trying to dereference a pointer that has not been initialised:
var value *float32
declares a pointer to a float32, but does not initialise it, resulting in a nil pointer.
v := float64(*value)
Then tries to dereference value but as we just identified, value is nil - it doesn't point to anything so asking for what it points to is bound to result in an error.
However, your code is actually fine, as long as you have a *float32 that actually points to a float32, which we can see if we add an actual float32 variable and initialise value to point to that:
package main
import "fmt"
func main() {
var vv float32 = 3.14159
var value *float32 = &vv
v := float64(*value)
vp := &v
fmt.Println(vp)
}
Which will output the address of the float64 value.
However, be aware that a float64 is not just a float32 that takes up twice as many bytes. The precision and the internal representation are different, as can be seen with a further modification to the code:
func main() {
var vv float32 = 3.14159
var value *float32 = &vv
v := float64(*value)
fmt.Println(vv)
fmt.Println(v)
}
you should see output similar to:
3.14159
3.141590118408203
This is not a bug, this is the result of the different internal representation of a float64 vs float32.
There is no way to guarantee the exact same value in these different types - each has characteristics that make some values literally impossible to represent, from which it follows that it is impossible to guarantee that float32(v) == float64(v) for every v.
This is also why you cannot simply type-cast the pointer:
vp := *float64(value)
This is illegal because a pointer to a float64 is pointing to something fundamentally different than a pointer to a float32.
By contrast you can simply typecast a *int32 as a *int64.
One method is to write a function to safely convert the float32 pointer to a float64 pointer.
package main
import "fmt"
func main() {
var value *float32
v := float32ToFloat64(value)
fmt.Println(v)
val := float32(1.2)
p := float32ToFloat64(&val)
fmt.Println(*p)
}
func float32ToFloat64(value *float32) *float64 {
if value == nil {
return nil
}
v := float64(*value)
return &v
}

Single function iterate a map or slice with generics [duplicate]

I am testing out generics in go 1.18 and took a look at this example.
I would like to recreate that example but instead be able to pass in a slice of int or slice of float instead, and in the function I'll just sum up everything in the slice.
This is when I ran into some issues just iterating the slice. This is what I tried:
package main
import "fmt"
// NumberSlice constraint
type NumberSlice interface {
[]int64 | []float64
}
func add[N NumberSlice](n N) {
// want: to range over n and print value of v
for _, v := range n {
fmt.Println(v)
}
}
func main() {
ints := []int64{1, 2}
add(ints)
}
I got the error:
cannot range over n (variable of type N constrained by NumberSlice) (N has no core type)
How do I accomplish this?
A core type, for an interface (including an interface constraint) is defined as follows:
An interface T has a core type if one of the following conditions is
satisfied:
There is a single type U which is the underlying type of all types in the type set of T
or the type set of T contains only channel types with identical element type E, and all directional channels have the same direction.
Your interface constraint has no core type, because it has two underlying types: []int64 and []float64.
Therefore you can't use it where a core type is required. Notably range and make.
You can change the interface to require the base types, and then specify the slice in the function signature:
// still no core type...
type Number interface {
int64 | float64
}
// ...but the argument will be instantiated with either int64 or float64
func add[N Number](n []N) {
for _, v := range n {
fmt.Println(v)
}
}
This also works, but it's way more verbose:
type NumberSlice[N int64 | float64] interface {
// one core type []N
~[]N
}
func add[S NumberSlice[N], N int64 | float64](n S) {
for _, v := range n {
fmt.Println(v)
}
}
Could something like this work for you?
package main
import "fmt"
type NumberOrFloat interface {
int64 | float64
}
func add[N NumberOrFloat](n []N) {
for _, v := range n {
fmt.Println(v)
}
}
func main() {
ints := []int64{1, 2}
add(ints)
}
The difference here is that you define type constraints on array elements (not on array types): []N

What's the reason for having methods outside the definition of the struct?

Why do we have the methods declared outside the type definition of the struct? E.g.:
type antenna struct {
name string
length float32
girth float32
bloodtype string
}
func (p *antenna) extend() {
p.length += 10
}
It seems to me that the method could be part of the struct? (Let's ignore for now that structs are supposed to be value types)
type antenna struct {
name string
length float32
girth float32
bloodtype string
func extend() {
length += 10
}
}
This would be more similar to traditional OOP. I didn't find any good explanations of why it is done the way it is besides "structs are value-types and classes are reference-types". I know the difference, but it's not a satisfactory answer to me. In any way the method has to be called like this:
var x = antenna()
x.extend()
So what's the point of separating the the struct and methods? Having them visually grouped together in the code - as in typical OOP languages - seems useful to me?
TLR: Code reuse, and Consistency.
1 - This enables to reuse methods:
This is the key design principle of the interface type in Go - let me make it more clear with an example: Consider you need to sort an slice of int (try it here):
a := []int{1, 3, 2, 5, 4}
sort.Ints(a) // sort.Sort(sort.IntSlice(a))
fmt.Println(a) // [1 2 3 4 5]
You simply call sort.Ints(a) which then calls Sort(IntSlice(a)) inside the standard library:
type IntSlice []int
func (x IntSlice) Len() int { return len(x) }
func (x IntSlice) Less(i, j int) bool { return x[i] < x[j] }
func (x IntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
sort.IntSlice attaches the 3 methods of sort.Interface: Len, Less, and Swap to the type []int, to call:
// Sort sorts data in ascending order as determined by the Less method.
// It makes one call to data.Len to determine n and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
n := data.Len()
quickSort(data, 0, n, maxDepth(n))
}
So you are able to reuse methods from the standard library, and you don't need to reimplement it again.
2- You may define your own types, See this example - There is no inside here for this named type - so methods must be outside of this type:
package main
import "fmt"
type num int32
func (p *num) inc() {
*p++
}
func main() {
p := num(100)
p.inc()
fmt.Println(p) // 101
}
The above named type num versus this user defined type: By design this makes the Go language consistent for both types:
type Animal struct {
Name string
moves []move.Direction
}
func (p *Animal) Walk(dir move.Direction) {
p.moves = append(p.moves, dir)
}
See also:
In Go is naming the receiver variable 'self' misleading or good practice?

Map as a method receiver

Does anyone know why map can be used as a value receiver, but when working with slices only the pointer receiver can be used? Why the map is changing after the method call?
Example for map:
package main
import (
"fmt"
)
type hashMap map[string]int
func (s hashMap) Add(k string, v int) {
s[k] = v
}
func main() {
var s hashMap
s = make(hashMap, 0)
fmt.Println(s)
s.Add("abc", 15)
fmt.Println(s)
}
Output:
map[]
map[abc:15]
Example for slice:
package main
import (
"fmt"
)
type slice []int
func (s *slice) Add(v int) {
(*s) = append(*s, v)
}
func main() {
var s slice
s = make(slice, 0)
fmt.Println(s)
s.Add(15)
fmt.Println(s)
}
Output:
[]
[15]
A map variable, after make, is a pointer to the map header: *hmap. The map pointer is passed by value
// A header for a Go map.
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
// ../reflect/type.go. Don't change this structure without also changing that code!
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}
A slice variable is a struct: slice. The slice struct is passed by value.
type slice struct {
array unsafe.Pointer
len int
cap int
}
Map is receiver type while struct is value type,Value type. Hence when you call using map value changes after function call.

Idiomatic Type Conversion in Go

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!
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.
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
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.

Resources