This question already has an answer here:
Anonymous struct, difference between struct{}{} and {}
(1 answer)
Closed 10 months ago.
I came across this in lecture notes:
setCollection := map[string]struct{}{
"uniqElement1": {},
"uniqElement2": {},
"uniqElement3": {},
}
As I understand, {} here represents the empty struct, but I never saw this before. Does this always mean an empty struct? Also, when can we use this notation? This code doesn't work:
setCollection["newElem"] = {}
{ and } are syntax requirement of composite literal values.
Your first example uses a composite literal to create a map value, and inside that literal it uses other struct literals for the key values of the map. And the Spec allows to omit the inner type in the inner literal:
Within a composite literal of array, slice, or map type T, elements or map keys that are themselves composite literals may elide the respective literal type if it is identical to the element or key type of T. Similarly, elements or keys that are addresses of composite literals may elide the &T when the element or key type is *T.
Your second example tries to use {} not in a composite literal, and the compiler does not know what type you want to use. So it's a compile time error. You have to be explicit in the second example:
setCollection["newElem"] = struct{}{}
Where struct{} is the type, and struct{}{} is a composite literal value (of type struct{}).
See related: How do struct{} and struct{}{} work in Go?
Related
I have tried to use generics with Go, but I don't really understand when we use any or comparable as type parameter. Can someone help to understand these?
It depends on what / how you want to use values of the parameter type. Constraints restrict what you can do with values of those types.
any is an alias for interface{} which allows any type. If a parameter can be of any type, that basically won't allow you to do anything with it because you have no guarantee what it will be.
The comparable constraints only allows types that are comparable, that is, the == and != operators are allowed to use on values of them. This is good if you want to use the type as a key in a map (maps require key types to be comparable), or if you you want to find an element in a slice, and you want to use the == operator to compare the elements to something.
As an example, let's write a generic map-get function:
func get[K comparable, V any](m map[K]V, key K) V {
return m[key]
}
The K key type must be comparable, else it cannot be used as the key type of some map (m[K]V in the example). V on the other hand shouldn't be constrained, the value type may be anything, and we're not doing anything with it (just returning a value of type V), so using any here is the best choice.
Another example, a slice-find function:
func find[V comparable](what V, s []V) int {
for i, v := range s {
if v == what {
return i
}
}
return -1
}
find() returns the index of the first occurrence of what in the slice s, and if it's not in the slice, returns -1. The type parameter V here must be comparable, else you couldn't write v == what, using V any would be a compile-time error. The constraint comparable ensures this find() function can only be instantiated with types (and called with values) where the == operator is defined and allowed.
The difference between comparable and any will change with Go 1.20 (Q1 2023) and (accepted) the proposal "56548: spec: allow basic interface types to instantiate comparable type parameters".
any will implement the comparable constraint (which it does not before Go 1.20).
Go 1.20-rc1 states:
Comparable types (such as ordinary interfaces) may now satisfy comparable constraints, even if the type arguments are not strictly comparable (comparison may panic at runtime).
This makes it possible to instantiate a type parameter constrained by comparable (e.g., a type parameter for a user-defined generic map key) with a non-strictly comparable type argument such as an interface type, or a composite type containing an interface type.
The principle is:
After substitution, each type argument must satisfy the constraint (instantiated, if necessary) of the corresponding type parameter. Otherwise instantiation fails.
With "satisfy" being:
A type T satisfies a constraint interface C if
T implements C; or
C can be written in the form interface{ comparable; E }, where E is a basic interface and T is comparable and implements E.
Example:
Currently, any does not implement the comparable constraint.
With the proposed change any will be permitted as type argument for comparable: comparable can be written as interface{ comparable; E } and thus the new rule applies, and any is spec-comparable and implements E (where E is the empty interface in this case).
Currently, the type parameter P in the type parameter list
[P interface{ comparable; fmt.Stringer }]
cannot be instantiated with the type S
type S struct {
data any
}
func (S) String() string
because S is not strictly comparable.
With the proposed change, S must only be spec-comparable (which it is) and implement fmt.Stringer (which it does).
("spec-comparable" are for types of comparable operands)
(as opposed to "strictly comparable", which is for the types in comparable, namely the set of (non-interface) types for which == and != are defined and for which these operations are guaranteed to not panic)
The implementation as started:
CL 453979: "cmd/compile: enable new comparable semantics by default"
CL 453978: "go/types, types2: make the new comparable semantics the default"
This question already has answers here:
nil slices vs non-nil slices vs empty slices in Go language
(3 answers)
Closed 11 months ago.
Option 1
var employees []Employee
session.Employees = employees
Option 2
session.Employees = []Employee{}
What, if any, is the difference in the two Golang code options, with respect to session.Employees after execution?
Your first version assigns the value of the employees variable to session.Employees. It will be the zero value of the type []Employee, which is nil. You could simply write this as:
session.Employees = nil
Your second version assigns the value of a composite literal, which will be an empty (length=0, capacity=0) but non-nil slice.
See related questions:
nil slices vs non-nil slices vs empty slices in Go language
What is the point of having nil slice and empty slice in golang?
Correct way to initialize empty slice
I am implementing a bit-vector in Go:
// A bit vector uses a slice of unsigned integer values or “words,”
// each bit of which represents an element of the set.
// The set contains i if the ith bit is set.
// The following program demonstrates a simple bit vector type with these methods.
type IntSet struct {
words []uint64 //uint64 is important because we need control over number and value of bits
}
I have defined several methods (e.g. membership test, adding or removing elements, set operations like union, intersection etc.) on it which all have a pointer receiver. Here is one such method:
// Has returns true if the given integer is in the set, false otherwise
func (this *IntSet) Has(m int) bool {
// details omitted for brevity
}
Now, I need to return an empty set that is a true constant, so that I can use the same constant every time I need to refer to an IntSet that contains no elements. One way is to return something like &IntSet{}, but I see two disadvantages:
Every time an empty set is to be returned, a new value needs to be allocated.
The returned value is not really constant since it can be modified by the callers.
How do you define a null set that does not have these limitations?
If you read https://golang.org/ref/spec#Constants you see that constants are limited to basic types. A struct or a slice or array will not work as a constant.
I think that the best you can do is to make a function that returns a copy of an internal empty set. If callers modify it, that isn't something you can fix.
Actually modifying it would be difficult for them since the words inside the IntSet are lowercase and therefore private. If you added a value next to words like mut bool you could add a if mut check to every method that changes the IntSet. If it isn't mutable, return an error or panic.
With that, you could keep users from modifying constant, non-mutable IntSet values.
I'm wondering why it's not possible to do the following in go:
func main() {
stuff := []string{"baz", "bla"}
foo("bar", stuff...)
}
func foo(s ...string) {
fmt.Println(s)
}
In my understanding, slice... "explodes" the slice so it can be used for multi argument function calls. So the above example should actually expand to foo("bar", "baz", "bla").
foo(stuff...) works as expected, no surprises here, but in the example above, the compiler complains about too many arguments.
Is this a desired limitation? I'm coming from a ruby background where a foo("bar", *stuff) is perfectly fine (and is, at least in my book, the same thing), that's why this surprises me.
The value for a variadic argument can be specified either by enumerating the elements, or using an existing slice, specified by its name followed by ....
You want to mix the 2 possible ways which is not permitted by the Go Language Specification (Passing arguments to ... parameters).
If the first form is used (enumerating the elements):
The value passed [as the variadic parameter] is a new slice of type []T with a new underlying array whose successive elements are the actual arguments.
If the latter is used (passing an existing slice followed by ...) no new slice is created, the one you pass is used as is. And the passed slice can only be used to specify the value of one – the final – variadic parameter. Attempting to pass both a single element and a slice will not match the signature (the parameter list in this case) of your function and you'll get an error:
too many arguments in call to foo
There is no actual "exploding" involved in Go, the term is just used in other languages to help visualize that the passed array or slice will not be an element of the variadic parameter but will be the value of variadic parameter itself.
Mixing the 2 would require to allocate a new slice because obviously the existing slice cannot be used.
The ugly way to get this to work is make it into a new variadic.
foo(append([]string{"bar"}, stuff...)...)
And if the order doesn't matter:
foo(append(stuff, "bar")...)
https://play.golang.org/p/mY6y0vScfPB
The specification on this is at the "Passing arguments to ... parameters":
If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T.
If f is invoked with no actual arguments for p, the value passed to p is nil.
Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.
In your case, where stuff... works:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
But "bar", stuff... doesn't match either case specified above.
T, []T doesn't match f([]T).
I ran into this situation when preparing arguments to feed to external commands. If possible, just build an one argument slice, then you don't have to worry about combining scalars with slices when it's time to call the function:
package main
import "os/exec"
func main() {
stuff := []string{"bar"}
stuff = append(stuff, "baz", "bla")
exec.Command("name", stuff...).Run()
}
I've been trying to implement a function which can randomly select an element from any type of slice (like python's random.choice function)
func RandomChoice(a []interface{}, r *rand.Rand) interface{} {
i := r.Int()%len(a)
return a[i]
}
However, when I try to pass in a slice of type []float32 into the first argument this error occurs:
cannot use my_array (type []float32) as type []interface {} in function argument
is this a fundemental misuse of interface{}? is there some better way to do this?
Re: is there some better way to do this?
IMO there is. The OP approach is inefficient wrt to simple:
var v []T
...
// Select a random element of 'v'
e := v[r.Intn(len(v))]
...
Note that both of the approaches will panic for len(v) == 0 until a pre-check for this is made.
Using reflection:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
x := reflect.ValueOf(slice)
return x.Index(r.Intn(x.Len())).Interface()
}
From the language specification:
Two types are either identical or different.
Two named types are identical if their type names originate in the
same TypeSpec. A named and an unnamed type are always different. Two
unnamed types are identical if the corresponding type literals are
identical, that is, if they have the same literal structure and
corresponding components have identical types. In detail:
Two array types are identical if they have identical element types and
the same array length.
Two slice types are identical if they have
identical element types.
Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical
types, and identical tags. Two anonymous fields are considered to have
the same name. Lower-case field names from different packages are
always different.
Two pointer types are identical if they have identical base types.
Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types
are identical, and either both functions are variadic or neither is.
Parameter and result names are not required to match.
Two interface types are identical if they have the same set of methods with the same names and identical function types. Lower-case
method names from different packages are always different. The order
of the methods is irrelevant.
Two map types are identical if they have identical key and value types.
Two channel types are identical if they have identical value types and the same direction.
And:
A value x is assignable to a variable of type T ("x is assignable to
T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not
a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
Any value may be assigned to the blank identifier.
The combination of these two results that you can't assign a []MyType to an []interface{}.
Well, I can hardly believe after all the searching, that the first listed related question was: Type converting slices of interfaces in go which pretty much contains the answer.
Changing RandomChoice to use the InterfaceSlice function described in the answer to that question yields:
func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
islice := InterfaceSlice(slice)
i := r.Int()%len(islice)
return islice[i]
}
although apparently this answer is not very well performing, because it requires the entire slice to be converted to []interface{}...