How does this code work, and where is this syntax documented? - go

I found a github snippet custom unmarshaling JSON at https://gist.github.com/miguelmota/904f0fdad34eaac09c5d53098f960c5c. It works well, but I hate using code I don't understand.
Specifically, this part uses syntax I'm not familiar with:
type Alias MyStruct
aux := &struct {
SomeCustomType int64 `json:"someCustomType"`
*Alias
}{
Alias: (*Alias)(s),
}
I understand a new type, Alias is being declared, and that it has the same fields as MyStruct. aux is initialized as a pointer to a struct with a redefined field SomeCustomType.
What I've not seen before is the declaration of Alias within the aux struct - (*Alias)(s).
What is this actually doing? Where can I find the documentation on this piece of Go syntax?

The section { Alias: (*Alias)(s) } is not a declaration, it's a struct literal.
A struct literal sets the fields of a struct (in this case, an anonymous struct). Let's break it down:
The Alias: part is setting the embedded field of the struct. Since the struct embeds *Alias, it does not have a field name for it, and the type is used instead.
The (*Alias)(s) part is an explicit type conversion, changing whatever s is to the type *Alias (as long the types are compatible).

Related

Go generics: Invalid composite literal [duplicate]

This question already has an answer here:
Go generics: invalid composite literal type T
(1 answer)
Closed last month.
The following code results in the error "invalid composite literal type T".
package main
import "fmt"
func main() {
fmt.Println(createThing[foo]())
}
type thing interface {
foo | bar
}
type foo struct {
id int
a string
}
type bar struct {
id int
b int
}
func createThing[T thing, P *T]() P {
return &T{}
}
If I only include foo in interface thing, or remove a string and b int so foo and bar are exactly the same, the code will run without error. However, doesn't this defeat the purpose of generics? Why can't I instantiate a generic type like this, especially when I'm not even accessing any fields?
Possibly related to https://github.com/golang/go/issues/48522
Most generic types are not valid types for composite literals. This isn't a problem though, as there are other ways to create values of generic types.
To create a pointer to a new zero value:
func createThing[T thing]() *T {
return new(T)
}
Or to create a non-pointer zero value:
func createThing[T thing]() T {
var value T
return value
}
As for why the error occurs in this way, here's the explanation from the spec, revised to address your specific question.
For composite literals:
The LiteralType's core type T must be a struct, array, slice, or map type
What is the core type?
An interface T has a core type if [...] there is a single type U which is the underlying type of all types in the type set of T
No other interfaces have a core type.
What is the underlying type?
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its declaration.
A "type literal" can refer to a literal struct type, like struct{int id}. So, when foo and bar both have an underlying type of struct{int id}, then thing has a core type of struct{int id}, and so composite literals are possible. When foo and bar don't have the same underlying type, then thing has no core type, and composite literals are not possible, hence your error.
The formal definition may seem complicated, but the result and practical takeaway is simple: generic code is only capable of expressing common behaviour across the possible types. Besides in the special case where all underlying types are the same, literal values are not a common behaviour.

How to initialize an array of anonymous struct with generic field

I'd to learn whether it's possible to initialize an array of anonymous struct contains generic-field. Code below doesn't compile, moreover I couldn't find any sample related to:
testCases := type [K comparable, T Numeric] []struct {
name string
args map[K]T
expected int
}{
// items ...
{"integer", map[string]int{ "a":1 },
}
Without anonymous structs it's easy, but not the aimed:
type args[K comparable, T Numeric] struct {
m map[K]T
}
testCases := []struct {
name string
args args[string, int]
expected int
}{}
Thanks!
Type parameters are introduced so when you instantiate the type, you can give concrete types to type parameters. Given that, there is no sense in what you want to do. You want to create a generic anonymous type and instantiate it right away. You can't use this anonymous struct elsewhere (because it's anonymous), so leave out the type parameters and use the concrete types you'd instantiate the type parameters with if it would be a named type.
And to answer your original question: no, you cannot do this. The syntax does not allow this. There was a proposal to support this but was rejected: proposal: spec: generics: Anonymous generic aggregate types #45591. The workaround is to use a named struct type instead of the anonymous struct type, just as you suggested.

Why can't we embed slices or maps into Go structs

I learnt that it is not allowed to embed slices or maps into Go structs. But I found two workarounds to this:
Declare the slice or map outside the struct and embed it into the struct
var mySlice []int
type myStruct struct {
mySlice
}
I don't really understand this second workaround, but I found it's called Composition and it's done by just omitting the var keyword when declaring the slice or map within the struct
type myStruct struct {
mySlice []int
}
My first question is, can anyone explain why we can't directly embed slices and maps into a struct?
Second question: using the second workaround, is there any negative performance effect to that?
Third question: why do the first and second workaround work?
Spec: Struct types:
A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.
You can't embed a type like map[int]string, that's an anonymous type. Spec requires a type name. Even if you could embed that, it contains brackets which would make it disqualify from being an identifier, and again, spec says the unqualified type name acts as the field name.
Simply create a new type for it which you can then embed:
type mymap map[int]string
type s struct {
mymap
}
When you embed a type in a struct, you omit the field name. In your second attempt:
type myStruct struct {
mySlice []int
}
You did not omit the field name (it's mySlice), so this is not embedding, it's a regular, named field.

Type conversion vs type cast

In Go, because of it's static type language we can see lot of type conversion for example,
var x float64
var y =32
x=float64(32)
Even though Go supports type casting, as far as I know it's very rarely used in. Can someone explain why and usecases that type casting can be used. Following is a one example that use type casting.
type Common struct {
Gender int
From string
To string
}
type Foo struct {
Id string
Name string
Extra Common
}
type Bar struct {
Id string
Name string
Extra Common
}
foo:=Foo{
Id:"123",
Name:"damitha",
Extra: struct {
Gender int
From string
To string
}{Gender:1 , From:"xx", To:"yy" },
}
bar:=*(*Bar)(unsafe.Pointer(&foo))
fmt.Printf("%+v\n",bar)
Even this mapping also possible to achieve in more safer ways.
The unsafe shenanigans in the question are similar to type casting. These shenanigans are not needed. Use a conversion:
bar := *(*Bar)(&foo)
or more simply:
bar := Bar(foo)
The relevant quote from the specification is:
A non-constant value x can be converted to type T in any of these cases:
...
ignoring struct tags (see below), x's type and T have identical underlying types.
ignoring struct tags (see below), x's type and T are pointer types that are not defined types, and their pointer base types have identical underlying types.
The first point in the quote applies to Bar(foo) because Foo and Bar have identical underlying types.
The second point in the quote applies to the conversion (*Bar)(&foo) because:
*Foo and *Bar are pointer types
*Foo and *Bar are not defined types.
The base types Foo and Bar have the same underlying type.
Go supports neither type casting nor implicit type conversion while lot of static support languages like Java C/C++ supporting both. Go only supports for type conversion.

Unnamed arrays in structs in Go

So I can have
struct {
int
x []int
}
However,
struct {
int
[]int
}
will result in a syntax error: unexpected [, expecting }. Is there a way of having unnamed arrays in structs in Go? If so, what's the correct syntax?
Read The Go Programming Language Specification. In particular, the section on Struct types. The Go term to describe what you are looking for is an anonymous field.
Such a[n] [anonymous] field type must
be specified as a type name T or as a
pointer to a type name *T, and T
itself may not be a pointer type.
int is a type name. []int is neither a type name nor a pointer to a type name.
No, the type of an anonymous field must be a type name or a pointer to a type name. You could declare a new type name that is the same as an array type, and then it would work, but it wouldn't be exactly the same.

Resources