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}
Related
I just want to confirm if my understanding is correct about interface{}{}
Does interface{}{} mean a composite literal of interface type?
So, if I wanted to pass a composite type, lets say []byte as a interface{}, I should assign it to a variable of type interface{}{} and pass in that variable, whereas if I wanted to pass a non composite type, such as a int as a interface{}, I should assign it to a variable of type interface{} and pass in that variable.
Is my understanding correct on this?
interface{}{} is invalid syntax.
It is not an empty interface composite literal — there's no such thing. The following don't compile:
var a interface{}{} = "foo" // not a type
b := interface{}{} // not a value
From the specs Composite Literals:
Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated.
The valid syntax is interface{}, which is the empty interface, i.e. an interface with no name and empty method set.
If you compare it to a named interface, you will see that the extra set of curly braces at the end makes no sense:
type Fooer interface {
Foo() error
}{} // ???
You can instantiate an empty interface{} by converting nil:
a := (interface{})(nil)
Or you can declare a var of unnamed interface type:
type A struct {}
func (a A) Foo() string {
return "foo"
}
var a interface{ Foo() string } = A{}
To answer your question:
So, if I wanted to pass a composite type [...]
you can assign any value to a variable of type interface{}, that's about it. Whether the value is composite or not is irrelevant because all types satisfy the empty interface:
var a interface{} = []byte{0x01, 0x02}
var b interface{} = "string_literal"
Playground: https://play.golang.org/p/w-l1dU-6Hb5
The empty interface interface{} essentially says "I don't care". Anything can be passed as an empty interface. So for your examples they all could be stored as the empty interface.
Possibly a more interesting question is why you want to avoid types in the first place, and what you're trying to achieve. But for the purposes of using interface{} you can pass anything to it, even a "nil".
interface{} type of empty interface.
you assign []byte or int to any empty variable of empty interface (interface{} type) or you can pass it directly to function that exepts interface values.
When I define a custom type, it seems that the type of the underlying type makes a difference about whether I can pass it to a function as is or I need to convert it.
Question is:
Why does RuneFunc and StringMap work, but not Integer?
https://play.golang.org/p/buKNkrg5y-
package main
type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string
func main() {
//m := make(StringMap)
//mf(m)
var i Integer = 5
nf(i)
//var f func(rune) rune
//ff(f)
}
func mf(i map[string]string) {
}
func ff(i func(rune)rune) {
}
func nf(i int) {
}
Here, when I run this function called nf with Integer it complains although int is the underlying type. But when I call mf or ff they run successfully.
Integer and int
int and your new type Integer are 2 different, distinct types. Where Integer is expected, you have to pass a value of type Integer.
If you have an Integer value, you may use a simple type conversion to make it a value of type int, because the underlying type of Integer is int:
var i Integer = 5
nf(int(i))
What may be confusing and interesting at the same time is that you are allowed to pass an untyped constant without conversion:
nf(5)
Try these on the Go Playground.
The reason for this is in the Spec: Assignability:
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
[...]
x is an untyped constant representable by a value of type T.
5 is an untyped constant which is representable by a value of type int because the untyped constant 5 has a default type int, so it is representable by a value of type Integer (which has the same default type).
If you check the other assignability rules (not included in above quotation), none of them match the case where you attempt to pass a value of Integer for the parameter of type int, so that's not allowed.
See related question: Golang: Creating a Constant Type and Restricting the Type's Values
RuneFunc and func(rune) rune
The difference between this case and the previous one (Integer and int) is that int is a named type and func(rune) rune is not.
And there's an assignability rule which allows this:
x's type V and T have identical underlying types and at least one of V or T is not a named type.
So in this case:
var f RuneFunc
ff(f)
f is a named type, but the parameter type of ff() is func(rune) rune which is unnamed, so the assignment is allowed.
Go has a strict type system. Just because your type is merely an alias for int doesn't mean you can interchange the two freely, you'll still have to do a type conversion. Below is a working version of your main, here's the code on play ground: https://play.golang.org/p/BDTXnnG9Lg
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,
}
When I define a custom type, it seems that the type of the underlying type makes a difference about whether I can pass it to a function as is or I need to convert it.
Question is:
Why does RuneFunc and StringMap work, but not Integer?
https://play.golang.org/p/buKNkrg5y-
package main
type RuneFunc func(rune) rune
type Integer int
type StringMap map[string]string
func main() {
//m := make(StringMap)
//mf(m)
var i Integer = 5
nf(i)
//var f func(rune) rune
//ff(f)
}
func mf(i map[string]string) {
}
func ff(i func(rune)rune) {
}
func nf(i int) {
}
Here, when I run this function called nf with Integer it complains although int is the underlying type. But when I call mf or ff they run successfully.
Integer and int
int and your new type Integer are 2 different, distinct types. Where Integer is expected, you have to pass a value of type Integer.
If you have an Integer value, you may use a simple type conversion to make it a value of type int, because the underlying type of Integer is int:
var i Integer = 5
nf(int(i))
What may be confusing and interesting at the same time is that you are allowed to pass an untyped constant without conversion:
nf(5)
Try these on the Go Playground.
The reason for this is in the Spec: Assignability:
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
[...]
x is an untyped constant representable by a value of type T.
5 is an untyped constant which is representable by a value of type int because the untyped constant 5 has a default type int, so it is representable by a value of type Integer (which has the same default type).
If you check the other assignability rules (not included in above quotation), none of them match the case where you attempt to pass a value of Integer for the parameter of type int, so that's not allowed.
See related question: Golang: Creating a Constant Type and Restricting the Type's Values
RuneFunc and func(rune) rune
The difference between this case and the previous one (Integer and int) is that int is a named type and func(rune) rune is not.
And there's an assignability rule which allows this:
x's type V and T have identical underlying types and at least one of V or T is not a named type.
So in this case:
var f RuneFunc
ff(f)
f is a named type, but the parameter type of ff() is func(rune) rune which is unnamed, so the assignment is allowed.
Go has a strict type system. Just because your type is merely an alias for int doesn't mean you can interchange the two freely, you'll still have to do a type conversion. Below is a working version of your main, here's the code on play ground: https://play.golang.org/p/BDTXnnG9Lg
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.