基本类型 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package  mainimport  (    "fmt"      "math/cmplx"  ) var  (    ToBe   bool        = false      MaxInt uint64      = 1 <<64  - 1      z      complex128  = cmplx.Sqrt(-5  + 12i ) ) func  main ()     const  f = "%T(%v)\n"      fmt.Printf(f, ToBe, ToBe)     fmt.Printf(f, MaxInt, MaxInt)     fmt.Printf(f, z, z) } 
Go 的基本类型有Basic types:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 bool string int  int8  int16  int32  int64 uint uint8 uint16 uint32 uint64 uintptr byte // uint8 的别名 rune // int32 的别名      // 代表一个Unicode码 float32 float64 complex64 complex128 
这个例子演示了具有不同类型的变量。同时与导入语句一样,变量的定义“打包”在一个语法块中。
零值 
1 2 3 4 5 6 7 8 9 10 11 package  mainimport  "fmt" func  main ()     var  i int      var  f float64      var  b bool      var  s string      fmt.Printf("%v %v %v %q\n" , i, f, b, s) } 
变量在定义时没有明确的初始化时会赋值为 零值 。
零值是:
数值类型为 0 ; 
布尔类型为 false ; 
字符串为 “” (空字符串)。 
 
类型转换 
1 2 3 4 5 6 7 8 9 10 11 12 13 package  mainimport  (    "fmt"      "math"  ) func  main ()     var  x, y int  = 3 , 4      var  f float64  = math.Sqrt(float64 (x*x + y*y))     var  z int  = int (f)     fmt.Println(x, y, z) } 
表达式 T(v) 将值 v 转换为类型 T 。
一些关于数值的转换:
1 2 3 var  i int  = 42 var  f float64  = float64 (i)var  u uint  = uint (f)
或者,更加简单的形式:
1 2 3 i := 42  f := float64 (i) u := uint (f) 
与 C 不同的是 Go 的在不同类型之间的项目赋值时需要显式转换 。试着移除例子中 float64 或 int 的转换看看会发生什么。
类型推导 
1 2 3 4 5 6 7 8 package  mainimport  "fmt" func  main ()     v := 42       fmt.Printf("v is of type %T\n" , v) } 
在定义一个变量但不指定其类型时(使用没有类型的 var 或 := 语句), 变量的类型由右值推导得出。
当右值定义了类型时,新变量的类型与其相同:
但是当右边包含了未指名类型的数字常量时,新的变量就可能是 int 、 float64 或 complex128 。 这取决于常量的精度:
1 2 3 i := 42             f := 3.142          g := 0.867  + 0.5i   
尝试修改演示代码中 v 的初始值,并观察这是如何影响其类型的。
常量 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package  mainimport  "fmt" const  pi = 3.14 func  main ()     const  world = "世界"      fmt.println ("hello" , world)     fmt.println ("happy" , pi, "day" )     const  truth = true      fmt.println ("go rules?" , truth) } 
常量的定义与变量类似,只不过使用 const 关键字。
常量可以是字符、字符串、布尔或数字类型的值。
常量不能使用 := 语法定义。
数值常量 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  mainimport  "fmt" const  (    Big   = 1  << 100      Small = Big >> 99  ) func  needInt (x int )  int return  x*10  + 1  }func  needFloat (x float64 )  float64     return  x * 0.1  } func  main ()     fmt.Println(needInt(Small))     fmt.Println(needFloat(Small))     fmt.Println(needFloat(Big)) } 
数值常量是高精度的值。
一个未指定类型的常量由上下文来决定其类型。
指针 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  mainimport  "fmt" func  main ()     i, j := 42 , 2701      p := &i              fmt.Println(*p)      *p = 21               fmt.Println(i)       p = &j              *p = *p / 37         fmt.Println(j)  } 
Go 具有指针。 指针保存了变量的内存地址。
类型 *T 是指向类型 T 的值的指针。其零值是 nil 。
& 符号会生成一个指向其作用对象的指针。
*符号表示指针指向的底层的值。
1 2 fmt.Println(*p)  *p = 21           
这也就是通常所说的“间接引用”或“非直接引用”。
与 C 不同,Go 没有指针运算 。
结构体 
定义 
1 2 3 4 5 6 7 8 9 10 11 12 package  mainimport  "fmt" type  Vertex struct  {    X int      Y int  } func  main ()     fmt.Println(Vertex{1 , 2 }) } 
一个结构体( struct )就是一个字段的集合。
(而 type 的含义跟其字面意思相符。)
结构体字段 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  mainimport  "fmt" type  Vertex struct  {    X int      Y int  } func  main ()     v := Vertex{1 , 2 }     v.X = 4      fmt.Println(v.X) } 
结构体字段使用点号来访问。
结构体指针 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  mainimport  "fmt" type  Vertex struct  {    X int      Y int  } func  main ()     v := Vertex{1 , 2 }     p := &v     p.X = 1e9      fmt.Println(v) } 
结构体文法 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  mainimport  "fmt" type  Vertex struct  {    X, Y int  } var  (    v1 = Vertex{1 , 2 }       v2 = Vertex{X: 1 }       v3 = Vertex{}           p  = &Vertex{1 , 2 }  ) func  main ()     fmt.Println(v1, p, v2, v3) } 
结构体文法表示通过结构体字段的值作为列表来新分配一个结构体。
使用 Name: 语法可以仅列出部分字段。(字段名的顺序无关。)
特殊的前缀 & 返回一个指向结构体的指针。
数组 
1 2 3 4 5 6 7 8 9 10 11 package  mainimport  "fmt" func  main ()     var  a [2 ]string      a[0 ] = "Hello"      a[1 ] = "World"      fmt.Println(a[0 ], a[1 ])     fmt.Println(a) } 
类型 [n]T 是一个有 n 个类型为 T 的值的数组。
表达式
定义变量 a 是一个有十个整数的数组。
数组的长度是其类型的一部分,因此数组不能改变大小 。这看起来是一个制约,但是请不要担心; Go 提供了更加便利的方式来使用数组。
slice 
1 2 3 4 5 6 7 8 9 10 11 12 package  mainimport  "fmt" func  main ()     s := []int {2 , 3 , 5 , 7 , 11 , 13 }     fmt.Println("s ==" , s)     for  i := 0 ; i < len (s); i++ {         fmt.Printf("s[%d] == %d\n" , i, s[i])     } } 
一个 slice 会指向一个序列的值,并且包含了长度信息。
[]T 是一个元素类型为 T 的 slice。
对 slice 切片 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  mainimport  "fmt" func  main ()     s := []int {2 , 3 , 5 , 7 , 11 , 13 }     fmt.Println("s ==" , s)     fmt.Println("s[1:4] ==" , s[1 :4 ])          fmt.Println("s[:3] ==" , s[:3 ])          fmt.Println("s[4:] ==" , s[4 :]) } 
slice 可以重新切片,创建一个新的 slice 值指向相同的数组。
表达式
表示从 lo 到 hi-1 的 slice 元素,含两端。因此
是空的,而
有一个元素。
构造 slice 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package  mainimport  "fmt" func  main ()     a := make ([]int , 5 )     printSlice("a" , a)     b := make ([]int , 0 , 5 )     printSlice("b" , b)     c := b[:2 ]     printSlice("c" , c)     d := c[2 :5 ]     printSlice("d" , d) } func  printSlice (s string , x []int )     fmt.Printf("%s len=%d cap=%d %v\n" ,         s, len (x), cap (x), x) } 
slice 由函数 make 创建。这会分配一个零长度的数组并且返回一个 slice 指向这个数组:
为了指定容量,可传递第三个参数到 make:
1 2 3 b := make ([]int , 0 , 5 )  b = b[:cap (b)]  b = b[1 :]       
nil slice 
1 2 3 4 5 6 7 8 9 10 11 package  mainimport  "fmt" func  main ()     var  z []int      fmt.Println(z, len (z), cap (z))     if  z == nil  {         fmt.Println("nil!" )     } } 
slice 的零值是 nil 。
一个 nil 的 slice 的长度和容量是 0。
向 slice 添加元素 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  mainimport  "fmt" func  main ()     var  a []int      printSlice("a" , a)          a = append (a, 0 )     printSlice("a" , a)          a = append (a, 1 )     printSlice("a" , a)          a = append (a, 2 , 3 , 4 )     printSlice("a" , a) } func  printSlice (s string , x []int )     fmt.Printf("%s len=%d cap=%d %v\n" ,         s, len (x), cap (x), x) } 
向 slice 添加元素是一种常见的操作,因此 Go 提供了一个内建函数 append 。 内建函数的文档对 append 有详细介绍。
1 func  append (s []T, vs ...T)  []T 
append 的第一个参数 s 是一个类型为 T 的数组,其余类型为 T 的值将会添加到 slice。
append 的结果是一个包含原 slice 所有元素加上新添加的元素的 slice。
如果 s 的底层数组太小,而不能容纳所有值时,会分配一个更大的数组。 返回的 slice 会指向这个新分配的数组。
range 
1 2 3 4 5 6 7 8 9 10 11 package  mainimport  "fmt" var  pow = []int {1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 }func  main ()     for  i, v := range  pow {         fmt.Printf("2**%d = %d\n" , i, v)     } } 
for 循环的 range 格式可以对 slice 或者 map 进行迭代循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 package  mainimport  "fmt" func  main ()     pow := make ([]int , 10 )     for  i := range  pow {         pow[i] = 1  << uint (i)     }     for  _, value := range  pow {         fmt.Printf("%d\n" , value)     } } 
可以通过赋值给 _ 来忽略序号和值。
如果只需要索引值,去掉  , value 的部分即可。
map 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package  mainimport  "fmt" type  Vertex struct  {    Lat, Long float64  } var  m map [string ]Vertexfunc  main ()     m = make (map [string ]Vertex)     m["Bell Labs" ] = Vertex{         40.68433 , -74.39967 ,     }     fmt.Println(m["Bell Labs" ]) } 
map 映射键到值。
map 在使用之前**必须用 make 而不是 new **来创建;值为 nil 的 map 是空的,并且不能赋值。
map 的文法 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  mainimport  "fmt" type  Vertex struct  {    Lat, Long float64  } var  m = map [string ]Vertex{    "Bell Labs" : Vertex{         40.68433 , -74.39967 ,     },     "Google" : Vertex{         37.42202 , -122.08408 ,     }, } func  main ()     fmt.Println(m) } 
map 的文法跟结构体文法相似,不过必须有键名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package  mainimport  "fmt" type  Vertex struct  {    Lat, Long float64  } var  m = map [string ]Vertex{    "Bell Labs" : {40.68433 , -74.39967 },     "Google" :    {37.42202 , -122.08408 }, } func  main ()     fmt.Println(m) } 
如果顶级的类型只有类型名的话,可以在文法的元素中省略键名。
修改 map 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package  mainimport  "fmt" func  main ()     m := make (map [string ]int )     m["Answer" ] = 42      fmt.Println("The value:" , m["Answer" ])     m["Answer" ] = 48      fmt.Println("The value:" , m["Answer" ])     delete (m, "Answer" )     fmt.Println("The value:" , m["Answer" ])     v, ok := m["Answer" ]     fmt.Println("The value:" , v, "Present?" , ok) } 
插入或修改元素 
访问元素 
删除元素 
检测某个键是否存在 
通过双赋值检测某个键存在:
如果 key 在 m 中, ok 为 true。否则, ok 为 false,并且 elem 是 map 的元素类型的零值。
同样的,当从 map 中读取某个不存在的键时,结果是 map 的元素类型的零值。
函数值 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package  mainimport  (    "fmt"      "math"  ) func  main ()     hypot := func (x, y float64 )  float64          return  math.Sqrt(x*x + y*y)     }     fmt.Println(hypot(3 , 4 )) } 
函数也是值。
函数的闭包 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package  mainimport  "fmt" func  adder ()  func (int )  int     sum := 0      return  func (x int )  int          sum += x         return  sum     } } func  main ()     pos, neg := adder(), adder()     for  i := 0 ; i < 10 ; i++ {         fmt.Println(             pos(i),             neg(-2 *i),         )     } } 
Go 函数可以是闭包的。闭包是一个函数值,它来自函数体的外部的变量引用。函数可以对这个引用值进行访问和赋值;换句话说这个函数被“绑定”在这个变量上。
例如,函数 adder 返回一个闭包。每个闭包都被绑定到其各自的 sum 变量上。
深入阅读 
Go 切片:用法和本质