1. 基本类型

Go 的基本类型有三类:

booltruefalse&&||!stringrunelen()intint8int16int32int64uintuint8uint16uint32uint64uintptrbyterunefloat32float64complex64complex128
byteuint8runeint32𪸿U+2AE3F175679
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8  // Go 1.9 开始用户也可以声明自定义的类型别名(type alias)

// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32
"hello"'𪸿'
2. 变量
var
package main

import "fmt"

// 包级别声明的变量会在 main 入口函数执行前完成初始化
var a int = 10

func main() {
  fmt.Printf("%T %v\n", a, a)

  // 局部变量将在声明语句被执行到的时候完成初始化
  var b int = 20
  fmt.Printf("%T %v\n", b, b)

  // 可以在一个声明语句中同时声明一组变量:变量类型相同时,保留最后的类型即可
  var c, d bool = true, false
  fmt.Printf("%T %v\n", c, c)
  fmt.Printf("%T %v\n", d, d)

  // 可以在一个声明语句中同时声明一组变量:变量类型不同时,不能分别写类型,由 Go 自动进行类型推导
  var e, f = "hello", 3.14
  fmt.Printf("%T %v\n", e, e)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
int 10
int 20
bool true
bool false
string hello
float32 3.14
*/
分组
var (
  b bool    = true
  s string  = "hello"
  i int     = 10
  f float64 = 3.14
)

一组变量也可以通过调用一个函数,由函数返回的多个返回值初始化:

var f, err = os.Open(name)  // os.Open returns a file and an error  表达式在运行时(runtime)被计算

2.1 零值

零值(zero value)
false""0
package main

import "fmt"

func main() {
  var b bool
  var s string
  var i int
  var f float64
  fmt.Printf("%v %q %v %v\n", b, s, i, f)
}

/* Output:
false "" 0 0
*/

其它零值:

nil

零值初始化机制可以确保每个声明的变量总是有一个良好定义的值,因此在 Go 语言中不存在未初始化的变量。这个特性可以简化很多代码,而且可以在没有增加额外工作的前提下确保边界条件下的合理行为

2.2 类型推导

在声明一个变量而不指定其类型时,变量的类型由右值推导得出

package main

import "fmt"

func main() {
  var b, s, i, f = false, "hello", 10, 3.14
  fmt.Printf("%T %v\n", b, b)
  fmt.Printf("%T %v\n", s, s)
  fmt.Printf("%T %v\n", i, i)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
bool false
string hello
int 10
float64 3.14
*/

当右值声明了类型时,新变量的类型与其相同:

var i int
j := i  // j 也是一个 int

2.3 短变量声明

func main() {...}:=var:=
importvar:=
package main

import "fmt"

// var 声明变量可以出现在函数外
var b bool = false

// b := false  // 报错: syntax error: non-declaration statement outside function body

func main() {
  // var 声明变量也可以出现在函数内
  var s = "hello"

  // 短变量声明 := 只能出现在函数内
  i, f := 10, 3.14
  fmt.Printf("%T %v\n", b, b)
  fmt.Printf("%T %v\n", s, s)
  fmt.Printf("%T %v\n", i, i)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
bool false
string hello
int 10
float64 3.14
*/
:==

和普通 var 形式的变量声明语句一样,短变量声明语句也可以用函数的返回值来声明和初始化变量:

// 注意: f 和 err 至少有一个变量之前未被声明过,或者会报错 compile error: no new variables,此时只能使用 = 赋值操作
f, err := os.Open(name)
defer f.Close()

if err != nil {
  return err
}

要特别注意短变量声明语句的作用域范围:

package main

import (
  "fmt"
  "log"
  "os"
)

var cwd string

func init() {
  cwd, err := os.Getwd() // 不同代码块中的重名变量 cwd
  if err != nil {
    log.Fatalf("os.Getwd failed: %v", err)
  }
  // 如果注释掉下面的语句编译不通过,因为内部重声明的 cwd 变量未使用
  // compile error: cwd declared and not used
  fmt.Printf("Working directory = %s \n", cwd)
}

func main() {
  fmt.Printf("%T %q\n", cwd, cwd)
}

/* Output:
Working directory = D:\MyCode\go-in-action
string ""
*/
:=变量重声明
func foo() {
  var err error
  n, err := io.WriteString(os.Stdout, "Hello, everyone!\n") // err 为变量重声明
  ...
}
屏蔽:=
package main

import (
  "fmt"
  "log"
  "os"
)

var cwd string

func init() {
  var err error
  cwd, err = os.Getwd()  // 不使用 :=
  if err != nil {
    log.Fatalf("os.Getwd failed: %v", err)
  }
  // 即使注释掉下面的语句也不会报错了
  fmt.Printf("Working directory = %s \n", cwd)
}

func main() {
  fmt.Printf("%T %q\n", cwd, cwd)
}

/* Output:
Working directory = D:\MyCode\go-in-action
string "D:\\MyCode\\go-in-action"
*/

2.4 类型转换

T(v)vTcannot convert v (type a) to type b
package main

import "fmt"

func main() {
  // 等价于 var i int = 42
  i := 42
  fmt.Printf("%T %v\n", i, i)

  // 等价于 var f float64 = float64(i)
  f := float64(i)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
int 42
float64 42
*/
3. 常量
const
分组
const (
  b bool    = true
  s string  = "hello"
  i int     = 10
  f float64 = 3.14
)
:=
package main

import "fmt"

// const 声明常量可以出现在函数外
const b bool = false

func main() {
  // const 声明常量也可以出现在函数内
  const s = "hello"

  // const i  // 报错: missing value in const declaration,常量必须被明确赋值,没有零值的概念
  // const i, f := 10, 3.14  // 报错: syntax error: unexpected :=, expecting =

  // 类型推导
  const i, f = 10, 3.14

  fmt.Printf("%T %v\n", b, b)
  fmt.Printf("%T %v\n", s, s)
  fmt.Printf("%T %v\n", i, i)
  fmt.Printf("%T %v\n", f, f)

  // i = 20  // 报错: cannot assign to i,常量不可变
}

/* Output:
bool false
string hello
int 10
float64 3.14
*/