1. 变量和常量

golang中变量的定义结构是:var 变量名 类型。golang中内建变量类型有:

  • bool, string
  • (u)int, (u)int8, (u)int16, (u)int32, (u)int64, uintptr(指针)未指定长度时根据操作系统是多少位来决定
  • byte, rune(长度32位,相当于 char,解决多国语言问题)
  • float32, float64, complex64, complex128 可以看到golang中没有char, 只有rune

1.1 变量

  • 变量都有默认值
func variableZeroValue() {
	//golang 给定义的变量都会给定默认值,数值型默认是0, string默认值是“”空字符串(不是nil)
	var a int
	var s string
	fmt.Printf("%d %q\n", a, s) //输出:0 "", %q打印string时会打印出“”, 表示引用
}
  • 变量定义时赋初值,可以连续为多个变量赋值
func variableInitialValue() {
	var a, b int = 3, 4
	var s string = "abc"
	fmt.Println(a, b, s) //输出:3 4 abc
}
  • 变量定义时赋初值支持类型推导
func variableTypeDeduction() {
    //定义并赋值,可以不显式的指定类型
	var a, b, c, s = 3, 4, true, "def"
	fmt.Println(a, b, c, s) //输出:3 4 true def
}
  • 使用:=可以省略var,简短变量声明赋值,但是这个方式不能在func外使用
func variableShorter() {
	a, b, c, s := 3, 4, true, "def"
	b = 5
	fmt.Println(a, b, c, s) //输出:3 4 true def
}
  • 可以使用var ()一次定义多个变量,可以在func外使用,也可以在func内使用
var (
	aa = 3
	ss = "kkk"
)
func variablePrint() {
	fmt.Println(aa, ss) ///输出:3 true kkk
}
  • 类型转换都是强制的,没有默认的类型转换
func calcTriangle(a, b int) int {
	var c int
	// math.Sqrt(a*a + b*b) // 错误, a*a + b*b是int类型,Sqrt函数传入参数是float64, 需要强制转换
	// c = math.Sqrt(float64(a*a + b*b)) //错误, c是int类型,Sqrt函数返回float64, 需要强制转换
	c = int(math.Sqrt(float64(a*a + b*b))) //正确
	return c
}

1.2 常量和枚举

  • const数值可以作为各种类型使用
func consts() {
	const (
		filename = "abc.txt"
		a, b     = 3, 4
	)
	var c int
	c = int(math.Sqrt(a*a + b*b)) // 正确,const数值可以作为各种类型使用
	fmt.Println(filename, c) //输出:abc.txt 5
}

枚举是一类特殊的常量,golang中没有枚举的关键字,所以一般都是使用const表示

  • iota表示一组自增值, 可以参与运算
func enums() {
	const (
		cpp = iota // 0
		_          // 忽略掉1
		python     // 2
		golang     // 3
		javascript // 4
	)

	const (
		b = 1 << (10 * iota)
		kb //相当于 1 << (10 * 1)
		mb //相当于 1 << (10 * 2)
		gb
		tb
		pb
	)
	fmt.Println(cpp, javascript, python, golang) //输出: 0 4 2 3
	fmt.Println(b, kb, mb, gb, tb, pb) //输出: 1 1024 1048576 1073741824 1099511627776 1125899906842624
}

2. 条件语句

2.1 if语句

  • if的条件里不需要括号
  • if的条件里可以赋值
  • if的条件里赋值的变量作用域就在这个if语句里面
func printFile(filename string){
	if contents, err := ioutil.ReadFile(filename); err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%s\n", contents)
	}
}

2.2 switch语句

  • if一样,switch的判断条件里也是不需要括号的
  • switch会自动break,除非使用fallthrough
  • switch后可以没有表达式
func eval(a, b int, op string) int {
	var result int
	switch op {
	case "+":
		result = a + b
	case "-":
		result = a - b
	case "*":
		result = a * b
	case "/":
		result = a / b
	default:
		panic("unsupported operator:" + op)
	}
	return result
}

3. 循环

  • golang中没有while, 因为while的语义其实很容易用for替换
  • for 的条件里不需要括号
  • for 的条件里可以省略初始条件,结束条件,递增表达式
// 整数转二进制
func convertToBin(n int) string {
	result := ""
	for ; n > 0; n /= 2 {
		lsb := n % 2
		result = strconv.Itoa(lsb) + result
	}
	return result
}
  • 省略初始条件,相当于 while
for scanner.Scan(){
	fmt.Println(scanner.Text())
}
  • 省略所有条件,无限循环/死循环, 因为go是支持并发的,所以这种写法在go中很常见
for {
	fmt.Println("abc")
}

4. 函数

  • 函数的定义形式:
func 函数名(传入参数) [返回值]{
}
  • 可以返回多个返回值
func div(a, b int) (int, int) {
	return a / b, a % b
}
  • 函数返回多个值时可以起名字,但仅用于非常简单的函数,对于调用者而言没有区别
func div(a, b int) (q, r int) {
	q = a / b
	r = a % b
	return
}
  • 函数可以作为参数,函数式编程
func apply(op func(int, int) int, a, b int) int{
	fmt.Printf("Calling %s with %d, %d\n",
		runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(),
		a, b)
	return op(a, b)
}
  • go中只有可变参数列表,没有默认参数,函数重载
func sumArgs(values ...int) int {
	sum := 0
	for i := range values{
		sum += values[i]
	}
	return sum
}

5. 指针

  • golang中的指针是不能运算的,即不能像C/C++中那样将指针进行p++, p--, p = p+10这类的操作。正是因为指针可以运算导致C/C++的指针特别灵活
// 通过指针来交换值
func swap(a, b *int){
	*b, *a = *a, *b
}
  • Go语言的参数传递只有值传递一种方式, C/C++中有值传递和引用传递,Python/Java除了简单的自建类型基本都是引用传递。