Go: Types
Содержание
1 Basic Types
bool true or false string Numeric types: uint either 32 or 64 bits int same size as uint. for integer literals Go infers type int uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value uint8 the set of all unsigned 8-bit integers (0 to 255) uint16 the set of all unsigned 16-bit integers (0 to 65535) uint32 the set of all unsigned 32-bit integers (0 to 4294967295) uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615) int8 the set of all signed 8-bit integers (-128 to 127) int16 the set of all signed 16-bit integers (-32768 to 32767) int32 the set of all signed 32-bit integers (-2147483648 to 2147483647) int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807) float32 the set of all IEEE-754 32-bit floating-point numbers float64 the set of all IEEE-754 64-bit floating-point numbers. for floating-point literals Go infers float64 complex64 the set of all complex numbers with float32 real and imaginary parts complex128 the set of all complex numbers with float64 real and imaginary parts for complex literals Go infers complex128 byte alias for uint8 rune alias for int32 (represents a Unicode code point)
2 Enumerations
We can group together several constant declarations using the const keyword just once.
const ( Cyan = 0// 0 Magenta // 0 Yellow // 0 ) fmt.Println(Cyan, Magenta, Yellow) type ByteSize float64 const ( _ = iota // ignore first value by assigning to blank identifier KB ByteSize = 1 << (10 * iota) MB GB TB PB EB ZB YB ) fmt.Println(KB, TB, YB)
0 0 0 1024 1.099511627776e+12 1.2089258196146292e+24
2.1 iota
Within a constant declaration, the predeclared identifier iota represents successive untyped integer constants. It is reset to 0 whenever the reserved word const appears in the source and increments after each ConstSpec.
const ( // iota is reset to 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) const ( // iota is reset to 0 a = 1 << iota // a == 1 b = 1 << iota // b == 2 c = 3 // c == 3 (iota is not used but still incremented) d = 1 << iota // d == 8 ) const ( // iota is reset to 0 u = iota * 42 // u == 0 (untyped integer constant) v float64 = iota * 42 // v == 42.0 (float64 constant) w = iota * 42 // w == 84 (untyped integer constant) ) const x = iota // x == 0 (iota has been reset) const y = iota // y == 0 (iota has been reset) fmt.Printf("c2 = %d, d = %d, u = %d, v = %.01f, w = %d, x = %d y = %d", c2, d, u, v, w, x, y)
c2 = 2, d = 8, u = 0, v = 42.0, w = 84, x = 0 y = 0
3 Type conversion
The expression T(v) converts the value v to the type T. Go assignment between items of different type requires an explicit conversion which means that you manually need to convert types if you are passing a variable to a function expecting another type.
var i int32 = 42 var f32 float32 = float32(i) f64 := float64(f32) var u unit = unit(f)
4 Structs
A struct is a collection of fields/properties. You can define new types as structs or interfaces. You can think of a struct to be a light class that supports composition but not inheritance. You don’t need to define getters and setters on struct fields, they can be accessed automatically. However, note that only exported fields (capitalized) can be accessed from outside of a package.
package main import ( "fmt" "time" ) type Bootcamp struct { // Latitude of the event Lat float64 // Longitude of the event Lon float64 // Date of the event Date time.Time } func main() { fmt.Println(Bootcamp{ Lat: 34.012836, Lon: -118.495338, Date: time.Now(), }) }
{34.012836 -118.495338 2019-08-23 12:24:42.70724893 +0500 +05 m=+0.000209487}
A struct literal sets a newly allocated struct value by listing the values of its fields. You can list just a subset of fields by using the "Name:" syntax (the order of named fields is irrelevant when using this syntax). The special prefix & constructs a pointer to a newly allocated struct.
package main import ( "fmt" "time" ) type Point struct { X, Y int } type Bootcamp struct { // Latitude of the event Lat float64 // Longitude of the event Lon float64 // Date of the event Date time.Time } var ( p = Point{1, 2} // has type Point q = &Point{1, 2} // has type *Point r = Point{X: 1} // Y:0 is implicit s = Point{} // X:0 and Y:0 ) func main() { fmt.Println(p, q, r, s) // accessing fields using the dot notation event := Bootcamp{ Lat: 34.012836, Lon: -118.495338, } event.Date = time.Now() fmt.Printf("Event on %s, location (%f, %f)", event.Date, event.Lat, event.Lon) }
{1 2} &{1 2} {1 0} {0 0} Event on 2019-08-23 12:24:42.972590607 +0500 +05 m=+0.000230459, location (34.012836, -118.495338)
5 Initializing
Go supports the new expression to allocate a zeroed value of the requested type and to return a pointer to it.
x := new(int)
Following expressions using new and an empty struct literal are equivalent and result in the same kind of allocation/initialization.
package main import ( "fmt" ) type Bootcamp struct { Lat float64 Lon float64 } func main() { x := new(Bootcamp) y := &Bootcamp{} fmt.Println(*x == *y) }
true
6 Composition vs Inheritance
package main import "fmt" type User struct { Id int Name string Location string } type Player struct { Id int Name string Location string GameId int } func main() { p := Player{} p.Id = 42 p.Name = "Matt" p.Location = "LA" p.GameId = 90404 fmt.Printf("%+v", p) }
{Id:42 Name:Matt Location:LA GameId:90404}
Player struct has the same fields as the User struct but it also has a GameId field. It can be simplified by composing our struct.
type User struct { Id int Name, Location string } type Player struct { User GameId int }
We can initialize a new variable of type Player two different ways.
package main import "fmt" type User struct { Id int Name, Location string } type Player struct { User GameId int } func main() { // 1. Using the dot notation to set the fields p1 := Player{} p1.Id = 42 p1.Name = "Matt" p1.Location = "LA" p1.GameId = 90404 fmt.Printf("%+v", p1) // 2. Use struct literal p2 := Player{ User{Id: 42, Name: "Matt", Location: "LA"}, 90404, } fmt.Printf( "Id: %d, Name: %s, Location: %s, Game id: %d\n", p2.Id, p2.Name, p2.Location, p2.GameId) // Directly set a field defined on the Player struct p2.Id = 11 fmt.Printf("%+v", p2) }
{User:{Id:42 Name:Matt Location:LA} GameId:90404}Id: 42, Name: Matt, Location: LA, Game id: 90404 {User:{Id:11 Name:Matt Location:LA} GameId:90404}
Because our struct is composed of another struct, the methods on the User struct is also available to the Player.
package main import "fmt" type User struct { Id int Name, Location string } type Player struct { User GameId int } func (u *User) Greetings() string { return fmt.Sprintf("Hi %s from %s", u.Name, u.Location) } func main() { p := Player{} p.Id = 42 p.Name = "Matt" p.Location = "LA" fmt.Println(p.Greetings()) }
Hi Matt from LA