Printing variables changes the previous code results [duplicate] - go

This question already has answers here:
why struct arrays comparing has different result
(1 answer)
Addresses of slices of empty structs
(2 answers)
Closed 2 months ago.
I have the following code:
package main
import "fmt"
type MyStruct struct {
}
func main() {
a := &MyStruct{}
b := &MyStruct{}
fmt.Println(a == b)
fmt.Println(*a == *b)
}
Which as expected outputs
false
true
But, if I add two Print statements at the end like this:
package main
import "fmt"
type MyStruct struct {
}
func main() {
a := &MyStruct{}
b := &MyStruct{}
fmt.Println(a == b)
fmt.Println(*a == *b)
fmt.Println(&a)
fmt.Println(&b)
}
The output becomes something I did not expect:
true
true
0xc0000ae018
0xc0000ae020
Why does it become true in the first case?

From the Go language specification:
Pointers to distinct zero-size variables may or may not be equal.
MyStruct is struct{}, which is a zero-size type. Hence, a == b may be true or false.

Related

Generic type inference with dependent types in Go [duplicate]

This question already has an answer here:
cannot infer V: infer type parameter from constraint implementation
(1 answer)
Closed 5 months ago.
I want to have helpers for big maths from big package. One of them is IsZero which accepts big.(Int|Float|Rat) and returns true if this big number equals to zero and false if not.
I did it that way:
package main
import (
"fmt"
"math/big"
)
type Target interface {
big.Int | big.Float | big.Rat
}
type Comparable[T Target] interface {
Cmp(*T) int
}
func IsZero[C Comparable[T], T Target](a C) bool {
var t T
return a.Cmp(&t) == 0
}
And it works if I specify generic arguments explicitly:
func main() {
fmt.Println(IsZero[Comparable[big.Int], big.Int](big.NewInt(0)))
}
But if I try to make Go infer them for me, it doesn't work:
func main() {
fmt.Println(IsZero(big.NewInt(0)))
}
./prog.go:25:20: cannot infer T (prog.go:18:30)
Is there a possible workaround for this?
"Is there a possible workaround for this?" No, except hope inference will be smarter in the next Go version. –
Volker
Your can only simplify IsZero function:
func IsZero[T Target](a Comparable[T]) bool {
var t T
return a.Cmp(&t) == 0
}
func main() {
fmt.Println(IsZero[big.Int](big.NewInt(0)))
var b Comparable[big.Int] = big.NewInt(0)
fmt.Println(IsZero(b))
}

Why is the slice field of a struct not appended to? [duplicate]

This question already has answers here:
Assign a new value to a struct field
(2 answers)
Closed 10 months ago.
The output of the following code surprises me:
package main
import (
"fmt"
)
type Thing struct {
mappings map[string]int
orderings []string
}
func NewThing() Thing {
t := Thing{}
t.mappings = make(map[string]int)
return t
}
func (t Thing) Add(s string) {
t.mappings[s] = 1
t.orderings = append(t.orderings, s)
}
func main() {
t := NewThing()
t.Add("foo")
if len(t.mappings) == len(t.orderings) {
fmt.Printf("Equal lengths: %v versus %v", t.mappings, t.orderings)
} else {
fmt.Printf("Unequal lengths: %v versus %v", t.mappings, t.orderings)
}
}
When run on the playground (https://play.golang.org/p/Ph67tHOt2Z_I) the output is this:
Unequal lengths: map[foo:1] versus []
I believe I'm treating the slice correctly; from my understanding it is initialized to nil in NewThing(), and is appended to in Add() (ensuring that the value returned from append is only assigned to its first argument).
Am I missing something incredibly obvious?
I looked at the following resources for an explanation:
https://gobyexample.com/slices - only uses either slice literals (i.e. not a struct field) or slices with set capacities, and I will not know the final size of t.orderings. It's my understanding that append should perform the extension and allocation automatically.
https://go.dev/blog/slices-intro - again, all demonstrations use slice literals. If the fields are moved out of the struct things work as expected. It's only once in the struct that this behavior occurs.
https://yourbasic.org/golang/gotcha-append/ - while it does describe behavior where append does not work as expected, the explanation involves append reusing memory when the slice has enough capacity for a new element, causing unexpected behavior when attempts to append the same array to two different copies. In my case, there is no reassignment of slice operations such as the one in this article, which is discouraged (some_var = append(some_other_var, elem)).
And I looked at the following questions for inspiration:
Go - append to slice in struct: the solution to this question was to assign the result of append back to the field, which I have done.
Correct way to initialize empty slice: the explanation is that slices don't have to be initialized, and can be left as nil and "appended to with allocation", so I believe I'm fine not initializing Thing.orderings.
Incase you don't want to use a pointer ,you can declare a global variable for Thing struct and assign it with the value of t from add function.Here is the code for the same logic :
package main
import (
"fmt"
)
var thing Thing
type Thing struct {
mappings map[string]int
orderings []string
}
func NewThing() Thing {
t := Thing{}
t.mappings = make(map[string]int)
return t
}
func (t Thing) Add(s string) {
t.mappings[s] = 1
t.orderings = append(t.orderings, s)
thing = t
}
func main() {
t := NewThing()
t.Add("foo")
if len(thing.mappings) == len(thing.orderings) {
fmt.Printf("Equal lengths: %v versus %v", thing.mappings, thing.orderings)
} else {
fmt.Printf("Unequal lengths: %v versus %v", thing.mappings, thing.orderings)
}
}
Output:
Equal lengths: map[foo:1] versus [foo]

Go lang empty struct confusing feature [duplicate]

This question already has answers here:
why struct arrays comparing has different result
(1 answer)
Addresses of slices of empty structs
(2 answers)
Closed 2 years ago.
Here is my code:
package main
import (
"fmt"
)
type A struct{}
func main() {
var ad, bd A
res1 := &ad == &bd
res2 := ad == bd
fmt.Println(res1, res2)// true true
fmt.Printf("%p, %p\n", &ad, &bd) // 0x57bb60, 0x57bb60
}
Now if I comment the last line of main function like this:
package main
import (
"fmt"
)
type A struct{}
func main() {
var ad, bd A
res1 := &ad == &bd
res2 := ad == bd
fmt.Println(res1, res2) // false true
//fmt.Printf("%p, %p\n", &ad, &bd)
}
The program prints false true!
How can the last line influence the output?
Is there any special feature with the empty struct?
Or this problem is caused by the compiler?

Parameter that's a list of interface{} [duplicate]

This question already has an answer here:
Passing interface{} or []interface{} in Golang
(1 answer)
Closed 4 years ago.
I'm trying to create a function that prints out the len of a list passed into it, regardless of the type of the list. My naive way of doing this was:
func printLength(lis []interface{}) {
fmt.Printf("Length: %d", len(lis))
}
However, when trying to use it via
func main() {
strs := []string{"Hello,", "World!"}
printLength(strs)
}
It complains saying
cannot use strs (type []string) as type []interface {} in argument to printLength
But, a string can be used as a interface{}, so why can't a []string be used as a []interface{}?
You can use reflect package - playground
import (
"fmt"
"reflect"
)
func printLength(lis interface{}) {
fmt.Printf("Length: %d", reflect.ValueOf(lis).Len())
}

How can I cast from []interface{} to []int? [duplicate]

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 7 years ago.
I would like to get non duplicated []int.
I'm using set, but I don't know how to get []int from set.
How can I do that?
package main
import (
"fmt"
"math/rand"
"time"
"github.com/deckarep/golang-set"
)
func pickup(max int, num int) []int {
set := mapset.NewSet()
rand.Seed(time.Now().UnixNano())
for set.Cardinality() < num {
n := rand.Intn(max)
set.Add(n)
}
selected := set.ToSlice()
// Do I need to cast from []interface{} to []int around here?
// selected.([]int) is error.
return selected
}
func main() {
results := pickup(100, 10)
fmt.Println(results)
// some processing using []int...
}
There is no automatic way to do that. You need to create an int slice and copy into it:
selected := set.ToSlice()
// create a secondary slice of ints, same length as selected
ret := make([]int, len(selected))
// copy one by one
for i, x := range selected {
ret[i] = x.(int) //provided it's indeed int. you can add a check here
}
return ret

Resources