I am using this to create a struct without defining a separate type:
data := struct {
Product *domain.UserProduct
Options *[]domain.UserProductOption
}{
Product: userProduct,
Options: userProductOptions,
}
Is there a way to do the same without defining struct's structure, as number of fields and their types can inferred? Something like:
data := {
Product: userProduct,
Options: userProductOptions,
}
As of Go 1.17 there's nothing like that to infer the type of a struct.
There's been some discussion of this in the proposal #35304, but it's still open. To summarize the discussion:
foo({x: y}) - unreadable
data := _{x: y} - unreadable (?)
data := struct {x: y} - overloads the syntax of struct
data := tuple {x: y} - new keyword
. . .
You're welcome to participate in the discussion and/or submit your own proposal.
I would think something like data := struct _ {X: x, Y: y} should be the most in line with the philosophy of _ being used to omit things (as in this case we want to omit the struct definition).
Is there a way to do the same without defining struct's structure
No. The language doesn't allow it: in Composite literals, it is defined how these work:
Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated. They consist of the type of the literal followed by a brace-bound list of elements. Each element may optionally be preceded by a corresponding key.
CompositeLit = LiteralType LiteralValue .
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
SliceType | MapType | TypeName .
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
The place where you can have the literal value is in an element list:
// the struct type may be defined or literal
// defined type
type User struct {
Name string
}
// `{"John"}` is the literal value
foo := []User{{"John"}}
// literal type
// `{"John","john#myself.com"}` is the literal value
bar := []struct{Name string; Email string}{{"John","john#myself.com"}}
Related
Per this doc
type Point struct {
X, Y float64
_ struct{} // to prevent unkeyed literals
}
For Point{X: 1, Y: 1} everything will be fine, but for Point{1,1} you will get a compile error:
./file.go:1:11: too few values in &Pointer literal
Then I tried it in another data type _ byte and _ func() as below
type Pointer struct {
X, Y int
//_ byte // to prevent unkeyed literals
//_ func() // to prevent unkeyed literals
}
Both of them could prevent unkeyed literals. How does it prevent unkeyed literal? Is _ struct{} more efficient?
Unkeyed structs require you to specify all struct keys; it is an error if you don't specify the value for Y for example:
type Point struct {
X, Y float64
}
_ = Point{1}
// Output:
// ./main.go:8:8: too few values in Point{...}
The _ struct{} field doesn't really prevent unkeyed literals from the same package, as you can still do:
type Point struct {
X, Y float64
_ struct{} // to prevent unkeyed literals
}
_ = Point{1, 2, struct{}{}}
// Ugly and weird, but valid!
But in order to be able to assign values in struct fields from other packages they need to be "exported", that is, start with a capital letter, and _ doesn't, so this is an error:
_ = x.Point{1, 2, struct{}{}}
// Output
// ./main.go:6:28: implicit assignment of unexported field '_' in x.Point literal
There is nothing special about _; you can use anything else that doesn't start with a capital as well, such as noexport struct{} or whatnot.
Why struct{} and not byte or int? Well, those types allocate some amount of memory; for an int it's usually 8 bytes (or 4 bytes on a 32bit system), and byte is an alias for uint8 and allocates one byte.
struct{} on the other hand is an "empty" type (you can't assign anything to it) and won't use any memory. This is a very small optimisation, but if you're going to type something you might as well type struct{}.
Is all of this worth it? In my opinion it's not; if someone wants to use unkeyed struct literals with your library then that's their choice. Many lint tools will already warn on this, including the built-in go vet:
$ go vet main.go
./main.go:8:6: net/mail.Address composite literal uses unkeyed fields
How does it prevent unkeys literals works?
An unkeyed struct literal must specify all fields; by adding a field that cannot be specified from outside the package, it makes it impossible to use this format, so it requires a keyed literal. "Keyed" or "unkeyed" refers to whether the field names appear in the struct literal.
Does _ struct{} more efficient?
Yes, because it has a width of zero, so it doesn't consume any memory. All other types would increase the memory footprint of the struct unnecessarily.
Say we have a struct like so:
type Foo struct {
one string
two int
}
is it possible to declare literal values for this, something like:
type Foo struct {
one "foobar"
two int
}
or
type Foo struct {
one string
two 5678
}
basically for some objects we might have a hardcoded value for a field.
No, Go does not support literal types (a la TypeScript). Moreover, it actually can't, because of zero values.
Every type has a zero value which always exists and is always assignable to it. When variables of a type are declared, they are implicitly assigned to their type's zero value.
For integer (int, uint, int32, uint32, int64, uin64) or float (float32, float64) or complex (complex64 or complex128) types, this is just 0 (0.0 respectively).
For string types, this is the empty string "".
For slices, maps, pointers, channels, and interfaces, the zero value is nil.
For arrays (not slices: arrays are value-types with statically-known length); their zero value is just the zero value of the element type repeated to fill every slot
The zero value of a struct type is a struct all of whose fields are zero values
In any case, because it is always possible for any type to have a zero value, it would be incompatible to create a type which only allows for any particular non-zero value.
The best a literal type "foo" could possibly represent is that the value is either "foo" or the zero value "" (and no, Go doesn't support this anyway).
The closest you'll be able to do is a constant declaration, or a receiver function that just-so-happens to return a fixed value instead of an actual field.
Go is statically typed language, meaning every variable need to be declared with specific data type.
Setting default value for each fields inside a struct on declaration is not possible in Go. it's not supported.
But maybe you can do something like this.
type Foo struct {
one string
two int
}
func NewFoo() *Foo {
foo := new(Foo)
foo.one = "default value for one"
foo.two = 2
return foo
}
func main() {
objectWithDefaultValueForItsField := NewFoo()
}
What I did is basically just created a function with name isNew<struct name>(). This function returns a new object with default value for each of the fields defined.
Notable exception, for object that created from anonymous struct, the default value of the fields can be specified on declaration. i.e.
obj := struct {
one string
two int
}{
"default value for one",
2,
}
I don't understand the meaning of the double {}. This is not made clear in any learning material. Thanks.
variable <-struct {}{}
I don't understand the meaning of the double {}.
struct {}{}
In long form,
type T struct{}
var t = T{}
struct {} is a type, a struct with no fields, and struct {}{} is a composite literal, with zero values, of that type.
References:
The Go Programming Language Specification
Struct types
Composite literals
The zero value
variable is a variable of type channel (values are sent on it)
<- is a send operator
struct{} is type empty struct (has no fields)
{} makes it a struct literal (creates a value of the given struct type)
To better understand this form let me give you an example of a different struct type:
p := struct{ X, Y float64 }{0.0, 0.0}
var cache = struct {
sync.Mutex
mapping map[string]string
} {
mapping: make(map[string]string),
}
This looks like a struct with an embedded field sync.Mutex but I can't get my head around the second set of braces. It compiles and executes but what's up? Why does the label on the make instruction matter (it does) and the comma? Thanks...
The example you have is equivalent to:
type Cache struct {
sync.Mutex
mapping map[string]string
}
cache := Cache{
mapping: make(map[string]string),
}
Except in your example you do not declare a type of Cache and instead have an anonymous struct. In your example, as oppose to my Cache type, the type is the entire
struct {
sync.Mutex
mapping map[string]string
}
So think of the second pair of braces as the
cache := Cache{
mapping: make(map[string]string),
}
part.
make is a built in function that works similarly to C's calloc() which both initialize a data structure filled with 0'd values, in Go's case, certain data structures need to be initialized this way, other's (for the most part structs) are initialized with 0'd values automatically. The field there is needed so that the compiler now's cache.mapping is a empty map[string]string.
The comma there is part of Go's formatting, you can do Cache{mapping: make(map[string]string)} all on one line, but the moment the field's assignment is on a different line than the opening and closing braces, it requires a comma.
This is called a "struct literal" or an "anonymous struct" and is, in fact, how you always create structs in Go, it just may not be immediately obvious since you might be used to creating new types for struct types to make declaring them a bit less verbose.
An entire struct definition is actually a type in Go, just like int or []byte or string. Just as you can do:
type NewType int
var a NewType = 5 // a is a NewType (which is based on an int)
or:
a := 5 // a is an int
and both are distinct types that look like ints, you can also do the same thing with structs:
// a is type NewType (which is a struct{}).
type NewType struct{
A string
}
a := NewType{
A: "test string",
}
// a is type struct{A string}
a := struct{
A string
}{
A: "test string",
}
the type name (NewType) has just been replaced with the type of the struct itself, struct{A string}. Note that they are not the same type (an alias) for the purpose of comparison or assignment, but they do share the same semantics.
There is a piece of GO code I have seen in the GIN library and in the Google docs that look like the following
type (
T0 []string
T1 []string
T2 struct{ a, b int }
T3 struct{ a, c int }
T4 func(int, float64) *T0
T5 func(x int, y float64) *[]string
)
What I don't understand is, what this grouping is doing and what are some purposes of this implementation (there wasn't much in the docs that went over this topic unless I missed it)
another example from the gin library
type (
RoutesInfo []RouteInfo
RouteInfo struct {
Method string
Path string
Handler string
}
Engine struct {
RouterGroup
HTMLRender render.HTMLRender
allNoRoute HandlersChain
allNoMethod HandlersChain
noRoute HandlersChain
noMethod HandlersChain
pool sync.Pool
trees methodTrees
RedirectTrailingSlash bool
RedirectFixedPath bool
HandleMethodNotAllowed bool
ForwardedByClientIP bool
}
)
And lastly - sorry this is different topic but related to this one
var _ IRouter = &Engine{}
why is there a _ infront of IRouter? I know it's a blank identifier but what purpose does it have in that case
The code
type (
A int
B string
)
is functionality identical to
type A int
type B string
The grouping is just a way to organize code. The grouping is sometimes used to indicate that the types are related in some way.
The use of the blank identifier is explained in Specs: What's the purpose of the blank identifier in variable assignment?.
I think the first part of your question has already been answered. As for the second part, the code
var _ IRouter = &Engine{}
Creates a compile-time check that *Engine implements the IRouter interface. We are assigning a value of type *Engine to a variable that must be of the type IRouter. If a *Engine does not satisfy the interface then it won't compile.
This isn't strictly necessary but some people like to put it in where they define a type to ensure it always satisfies an intended interface.
Regarding 1st question
The statments shown are type declaration
From the Go language spec :
A type declaration binds an identifier, the type name, to a new type that has the same underlying type as an existing type, and operations defined for the existing type are also defined for the new type. The new type is different from the existing type.
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = identifier Type .
In layman terms, you can do :
type
e.g.
type Temperature uint8
type WeekTemp [7]Temperature
For underlying type,
Named instances of the boolean, numeric, and string types are predeclared.
Composite types are constructed using type literals
TypeLiteral = ArrayType | StructType | PointerType | FunctionType |
InterfaceType |
SliceType | MapType | ChannelType .
so you can also equivalently do :
type (
Temperature unit8
WeekTemp [7]Temperature
)
another example for composite type
type Tree struct {
leftChild, rightChild *Tree
}
For 2nd question,
Edited :
I wasn't aware of this but trying on go playground , it looks like the answer from jcbwlkr is indeed right.
So trying to compile
type MyInterface interface{
someMethod()
}
type MyType struct{}
var _ MyInterface = &MyType{}
will give this error
cannot use MyType literal (type *MyType) as type MyInterface in
assignment: *MyType does not implement MyInterface (missing
someMethod method)
So it indeed does a compile time check to make sure that Engine struct conforms to IRouter interface. neat