Go语法简略 - 基础篇

优秀的程序员应该不限于只用一两种语言,对各种语言都要有猎涉,这样才能在合适的应用下选择最合适的语言。但优秀的程序员至少需要精通一到两种语言,在众多的编程语言中,我选择 Go 和 Swift 作为自己之后20年内的主要编程语言。

本文主要记录 Go 的基础语法,方便查询。

0. Hello world

package main

import "fmt"

func main() {
  fmt.Println("Hello, 世界") // 语句结尾没有分号,当然这个也可以有
}

Go程序是由包组成的,从main package的main函数开始运行。import导入包”fmt”,调用Println打印”Hello, 世界”。

1. 变量

package main

import "fmt"

var c, python, java bool // 变量由var声明,类型放在最后

var j, k int = 1, 2 // 赋初值

// error := "这种赋值语句不允许出现在函数之外"
// const Pi := 3.14 - 常量不能使用:=
const Pi = 3.14

func main() {
  var i int
  fmt.Println(i, c, python, java) // 变量会被默认赋初值
  //: 0 false false false (//: 表示运行结果)

  var c, python, java = true, false, "no!"
  fmt.Println(j, k, c, python, java)
  //: 1 2 true false no!

  x := 3 // 自动识别变量类型
  l, m, n := true, false, "no!"
  fmt.Println(x, l, m, n)
  //: 3 true false no!

  fmt.Println(Pi)
  //: 3.14
}

2. 选择

package main

import (
  "fmt"
  "math"
)

func sqrt(x float64) string {
  if x < 0 { // 和C类似,去掉了小括号
    return sqrt(-x) + "i"
  }
  return fmt.Sprint(math.Sqrt(x))
}

func pow(x, n, lim float64) float64 {
  if v := math.Pow(x, n); v < lim { // if语句内可使用:=赋值
    return v
  } else {
    fmt.Printf("%g >= %g\n", v, lim) // else 语句
    //: 27 >= 20
  }
  // fmt.Println(v) - 变量v的作用域仅在if语句之内
  return lim
}

func main() {
  fmt.Println(sqrt(2), sqrt(-4))
  //: 1.4142135623730951 2i
  fmt.Println(pow(3, 2, 10), pow(3, 3, 20))
  //: 9 20
}

3. 循环

Go只有一种循环结构,for循环。

package main

import "fmt"

func main() {
  sum := 0
  for i := 0; i < 10; i++ { // 与C类似,取消了小括号
    sum += i
  }
  fmt.Println(sum)
  //: 45

  sum = 1
  for ; sum < 1000; { // 可省略部分参数
    sum += sum
  }
  fmt.Println(sum)
  //: 1024

  sum = 1
  for sum < 1000 { // 实现类似while的功能
    sum += sum
  }
  fmt.Println(sum)
  //: 1024

  for { // 死循环
    fmt.Println("I loop forever, please use ctrl+c and exit.");
  }
}

4. 函数

package main

import "fmt"

func add(x, y int) int { // 函数用func申明
  return x + y
}

func swap(x, y string) (string, string) {
  return y, x // 可以有多个返回值
}

func split(sum int) (x, y int) {
  x = sum * 4 / 9
  y = sum - x
  return // 根据参数列表返回相应的值,可读性差,少使用
}

func main() {
  fmt.Println(add(15, 24))
  //: 39

  a, b := swap("hub", "zdd")
  fmt.Printf("%v%v\n", a, b)
  //: zddhub

  fmt.Println(split(17))
  //: 7 10
}

5. 基础数据类型

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias for uint8

rune // alias for int32
     // represents a Unicode code point

float32 float64

complex64 complex128

The zero value is:
  0 for numeric types,
  false the boolean type, and
  "" (the empty string) for strings.

The expression T(v) converts the value v to the type T: // 转换
  var i int = 42
  var f float64 = float64(i)
  var u uint = uint(f)
or
  i := 42
  f := float64(i)
  u := uint(f)

6. Defer

package main

import "fmt"

func main() {
  name := "zddhub"
  defer fmt.Println(name) // 参数被存储,调用延后
  name = "hello,"
  fmt.Print(name)
  //: hello,zddhub

  // stacking defers
  fmt.Print("counting ")
  for i := 0; i < 10; i++ {
    defer fmt.Print(i, " ")
  }
  fmt.Print(" done ")
  //: hello,counting  done 9 8 7 6 5 4 3 2 1 0 zddhub
}

仔细分析第18行程序输出结果,defer按照栈的顺序,先调用后执行,并保存调用时的参数。

7. 指针

package main

import "fmt"

func main() {
  i, j := 42, 2701

  p := &i         // point to i
  fmt.Println(*p) // read i through the pointer
  *p = 21         // set i through the pointer
  fmt.Println(i)  // see the new value of i

  p = &j         // point to j
  *p = *p / 37   // divide j through the pointer
  fmt.Println(j) // see the new value of j

  var a [2]string
  a[0] = "hello"
  a[1] = "zddhub"
  pa := &a[0]

  fmt.Println(*pa)
  // fmt.Println(*(pa+1)) - 指针没有运算操作
}

8. 结构

Go没有class,只有struct

package main

import "fmt"

type Vertex struct { // 需要用type声明
  X, Y int
}

var ( // 多行声明和赋值的写法
  v1 = Vertex{1, 2}  // has type Vertex
  v2 = Vertex{X: 1}  // Y:0 is implicit
  v3 = Vertex{}      // X:0 and Y:0
  p  = &Vertex{1, 2} // has type *Vertex
)

func main() {
  fmt.Println(v1, p, v2, v3)
}

9. 内置结构

package main

import "fmt"

func main() {
  var a [2]string // 数组
  a[0] = "Hello"
  a[1] = "World"
  fmt.Println(a[0], a[1])
  fmt.Println(a)

  s := []int{2, 3, 5, 7, 11, 13} // Slices
  fmt.Println("s ==", s)
  for i := 0; i < len(s); i++ {
    fmt.Printf("s[%d] == %d\n", i, s[i])
  }
  fmt.Println("s[1:4] ==", s[1:4])
  fmt.Println("s[:3] ==", s[:3])
  fmt.Println("s[4:] ==", s[4:])

  // 创建Slices
  c := make([]int, 5)  // len(a)=5
  fmt.Println(c)
  b := make([]int, 0, 5) // len(b)=0, cap(b)=5
  b = b[:cap(b)] // len(b)=5, cap(b)=5
  b = b[1:]      // len(b)=4, cap(b)=4

  var z []int
  fmt.Println(z, len(z), cap(z))
  //: [] 0 0
  if z == nil {
    fmt.Println("nil!")
    //: nil!
  }
  z = append(z, 1)
  z = append(z, 2, 3, 4)
  fmt.Println(z)

  for i, v := range z { // range: 返回slice的index和value
    fmt.Printf("z[%d] = %d\n", i, v)
  }

  for _, v := range z { // _, 占位符, 不使用index
    fmt.Printf("%d\n", v)
  }

  for i := range z { // 不使用value,可以用_占位,或者只返回一个参数
    fmt.Printf("%d\n", i)
  }

  // Maps
  m := make(map[string]int)
  m["hello"] = 1
  m["zddhub"] = 2
  fmt.Println(m["hello"], m["zddhub"])

  var n = map[string]int{
    "hello": 1,
    "zddhub": 2, // - 需要换行时,这里的逗号不能省略
  }
  fmt.Println(n["hello"], n["zddhub"])
  delete(n, "hello")
}

如果你喜欢这篇文章,欢迎赞赏作者以示鼓励