Go 语言语法篇

作者:edelweiss 日期:2020年5月14日
参考资料 Go指南 http://tour.studygolang.com/


包、变量和函数

Go 语言参数类型位置在后

Go 语言的参数类型放在函数形参的后面,这点和C语言是相反的。

func add(x int, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}
Go 语言参数类型简化写法

Go 语言参数类型相同的情况下可以只在最后一个参数后面声明一次。

func add(x, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}
Go语言支持返回多个参数

值得注意的是,其返回值列表书写在函数的后面,后面跟着的是形参列表。

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}
Go语言的返回值可像一个变量一样使用

在返回的时候,只需要单独写一个return。

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}
var 关键字用来定义变量,名称在前类型在后。
var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}
Go 语言在定义初始化在一条语句中的时候,可以自动推导类型。
var i, j int = 1, 2

func main() {
    var c, python, java = true, false, "no!"
    fmt.Println(i, j, c, python, java)
}
Go 语言更多使用 := 的语法声明变量

这种语法必须在函数体内使用

func main() {
    var i, j int = 1, 2
    k := 3
    c, python, java := true, false, "no!"

    fmt.Println(i, j, k, c, python, java)
}

Go 语言的基本数据类型 TODO

bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名
// 代表一个Unicode码
float32 float64
complex64 complex128

变量在定义后没有初始化是零值

零值是:
数值类型为 0
布尔类型为 false
字符串为 ""(空字符串)。

Go 语言要求显示的类型转换
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)
}

常量的定义

定义常量用 const 关键字,上面的 := 语法定义不了常量。

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 (
    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))
}

流程控制语句

for 循环

Go 中的 for 循环 ( ) 被拿掉了

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))
}
for 把while 的工作也作了
func main() {
    sum := 1
    for sum < 1000 {
        sum += sum
    }
    fmt.Println(sum)
}
死循环
func main() {
    for {
    }
}
if 括号也没啦
func sqrt(x float64) string {
    if x < 0 {
        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 {
        return v
    } else {
        fmt.Printf("%g >= %g\n", v, lim)
    }
    // 这里开始就不能使用 v 了
    return lim
}
Go 语言中switch语句自带break

如果想要传递给下一个case块,使用fallthrough。

func main() {
    fmt.Print("Go runs on ")
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.", os)
    }
}
没有条件的switch 相当于switch true
func main() {
   t := time.Now()
   switch {
   case t.Hour() < 12:
       fmt.Println("Good morning!")
   case t.Hour() < 17:
       fmt.Println("Good afternoon.")
   default:
       fmt.Println("Good evening.")
   }
}
defer语句将会延迟到上层函数返回后执行
func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}
defer 栈

延迟的函数调用被压入一个栈中。当函数返回时, 会按照后进先出的顺序调用被延迟的函数调用。

func main() {
    fmt.Println("counting")

    for i := 0; i < 10; i++ {
        defer fmt.Println(i)
    }

    fmt.Println("done")
}

复杂类型 struct slice 和 map

指针
Go 具有指针。指针保存了变量的内存地址。

类型 *T 是指向类型T的值的指针。

var p *int

&符号会生成一个指向其作用对象的指针

i := 42
p = &i

*符号表示指针指向下一层的值

fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i

和C语言不同,Go没有指针运算。

结构体
结构体指针

结构体字段可以通过结构体指针来访问

结构体文法

类似于用一个匿名对象给一个新对象赋值?

使用 字段名: 语法可以仅列出部分字段。


package main

import "fmt"

type Vertex struct {
    X, Y int
}

var (
    v1 = Vertex{1, 2}  // 类型为 Vertex
    v2 = Vertex{X: 1}  // Y:0 被省略
    v3 = Vertex{}      // X:0 和 Y:0
    p  = &Vertex{1, 2} // 类型为 *Vertex
)

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

类型[n]T 是一个有 n 个类型为 T 的值的数组,数组的长度是其类型的一部分,因此数组不能改变大小。

slice

一个slice 会指向一个序列的值,并且包含了长度信息。
[]T 是一个元素类型为 T 的 slice。

package main

import "fmt"

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)

    for i := 0; i < len(p); i++ {
        fmt.Printf("p[%d] == %d\n", i, p[i])
    }
}
对 slice 切片

slice 可以重新切片,创建一个新的 slice 值指向相同的数组。

语法 slice[首:尾后迭代器]

package main

import "fmt"

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)
    fmt.Println("p[1:4] ==", p[1:4])

    // 省略下标代表从 0 开始
    fmt.Println("p[:3] ==", p[:3])

    // 省略上标代表到 len(s) 结束
    fmt.Println("p[4:] ==", p[4:])
}
构造 slice

slice 由函数 make 创建

b := make([]int, 0, 5) // len(b)=0, cap(b)=5
nil slice

slice 的零值是 'nil'

package main

import "fmt"

func main() {
    var z []int
    fmt.Println(z, len(z), cap(z))
    if z == nil {
        fmt.Println("nil!")
    }
}
向 slice 添加元素

Go 提供了一个内建函数 func append(s []T目标, vs元素 ...T) []T

package main

import "fmt"

func main() {
   var a []int
   printSlice("a", a)

   // append works on nil slices.
   a = append(a, 0)
   printSlice("a", a)

   // the slice grows as needed.
   a = append(a, 1)
   printSlice("a", a)

   // we can add more than one element at a time.
   a = append(a, 2, 3, 4)
   printSlice("a", a)
}

append 的第一个参数 s 是一个类型为 T 的数组,其余类型为T 的值将会添加到 slice。

append 的结果是一个包含原 slice 所有元素加上新添加的元素的 slice.

如果 s 的底层数组太小,而不能容纳所有值时,会分配一个更大的数组。返回的slice 会指向这个新分配的数组。

range 范围 for 循环
package main

import "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)
    }
}
range 可通过_忽略参数
map

map 在使用之前必须用 make 而不是 new 来创建;值为 nil 的 map 是空的,并且不能赋值。

package main
import "fmt"

type Vertex struct {
    Lat, Long float64
}

var m map[string]Vertex

func main() {
    m = make(map[string]Vertex)
    m["Bell Labs"] = Vertex{
        40.68433, -74.39967,
    }
    fmt.Println(m["Bell Labs"])
}
map的文法
package main

import "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键值对的时候可以省略值的类型
package main

import "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

在map中插入或者修改一个元素:m[key] = elem

获得元素:elem = m[key]

删除元素: delete(m, key)

检查某个键值是否存在 elem, ok = m[key] 如果这个值不存在,elem = nil值,ok = false

package main

import "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)
}
函数的闭包

闭包返回一个函数,且此函数跟函数体内部的变量绑定,(只初始化一次)。

package main

import "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),
        )
    }
}

#结果:
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90

方法和接口

方法

Go 没有类。然而,仍然可以在结构体类型上定义方法。方法接收者出现在啊 func 关键字和方法名之间的参数中。

package main

import(
    "fmt"
)

type Vertex struct {
    X, Y float64
}

func(v *Vertex) Sum() float64{
    return (v.X + v.Y)
}

func main(){
    v := &Vertex{3,4}
    fmt.Println(v.Sum())
}
接口

接口类型是由一组方法定义的集合,接口类型的变量可以存放实现接口方法的类型的对象。

package main

import (
    "fmt"
    "math"
)

type Abser interface {
    Abs() float64
}

func main() {
    var a Abser
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}

    a = f  // a MyFloat 实现了 Abser
    a = &v // a *Vertex 实现了 Abser

    // 下面一行,v 是一个 Vertex(而不是 *Vertex)
    // 所以没有实现 Abser。
    a = v

    fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
隐式接口

//TODO

并发

你可能感兴趣的:(Go 语言语法篇)