Skip to content

GO

``
go
package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("我最喜欢的数字是 ", rand.Intn(10))
}

****
go
func add(x int, y int) int {
	return x + y
}
/**
*当连续两个或多个函数的已命名形参类型相同时,
*除最后一个类型以外,其它都可以省略。
*/
func add(x, y int) int {
	return x + y
}
//函数可以返回任意数量的返回值。
func swap(x, y string) (string, string) {
	return y, x
}
****``
go
func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}
func c() (i int) {
    defer func() { i++ }()
    return 1
}

<font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">var</font>

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

<font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">int</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">uint</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">uintptr</font>

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

****
  • ``
  • ``
  • ``

``````
plain
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
plain
i := 42
f := float64(i)
u := uint(f)

````
plain
var i int
j := i // j 也是一个 int
``````
plain
i := 42           // int
f := 3.142        // float64
g := 0.867 + 0.5i // complex128

````
go
const Pi = 3.14

func main() {
    const World = "世界"
    fmt.Println("Hello", World)
    fmt.Println("Happy", Pi, "Day")

    const Truth bool = true
    fmt.Println("Go rules?", Truth)
}

****``
go
const (
	// 将 1 左移 100 位来创建一个非常大的数字
	// 即这个数的二进制是 1 后面跟着 100 个 0
	Big = 1 << 100
	// 再往右移 99 位,即 Small = 1 << 1,或者说 Small = 2
	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))
}

````

<font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">for</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">{ }</font>

go
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i
	}
	for ; sum < 1000; {
		sum += sum
	}
//此时你可以去掉分号,因为 C 的 while 在 Go 中叫做 for。
	sum := 1
	for sum < 1000 {
		sum += sum
	}
// 无限循环
	for {
	}

``````
go
	if x < 0 {
		return sqrt(-x) + "i"
	}
	if v := math.Pow(x, n); v < lim {
		return v
	} else {
		fmt.Printf("%g >= %g\n", v, lim)
	}

<font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">switch</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">if - else</font><font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">case</font>

````````````
go
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("macOS.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.\n", os)
    }
	switch time.Saturday {
	case today + 0:
		fmt.Println("今天。")
	case today + 1:
		fmt.Println("明天。")
	case today + 2:
		fmt.Println("后天。")
	default:
		fmt.Println("很多天后。")
	}

``````
go
	switch {
	case t.Hour() < 12:
		fmt.Println("早上好!")
	case t.Hour() < 17:
		fmt.Println("下午好!")
	default:
		fmt.Println("晚上好!")
	}

把这个调用函数推入一个栈中,这个函数return后再LIFO地调用它声明的defer。这导致其执行是可预测的。
go
func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}

panic类似于Exception或者error,发生时会逐层退出函数栈,但是退出函数时又可以触发已存储的defer函数

recover类似于catch的作用,但是仅能在defer函数内部使用,可捕获传递上来的错误并阻止冒泡

go
package main

import "fmt"

func main() {
    f()
    fmt.Println("Returned normally from f.")
}

func f() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
        }
    }()
    fmt.Println("Calling g.")
    g(0)
    fmt.Println("Returned normally from g.")
}

func g(i int) {
    if i > 3 {
        fmt.Println("Panicking!")
        panic(fmt.Sprintf("%v", i))
    }
    defer fmt.Println("Defer in g", i)
    fmt.Println("Printing in g", i)
    g(i + 1)
}

Calling g.

Printing in g 0

Printing in g 1

Printing in g 2

Printing in g 3

Panicking!

Defer in g 3

Defer in g 2

Defer in g 1

Defer in g 0

Recovered in f 4

Returned normally from f.

如果没有recover:

Calling g.

Printing in g 0

Printing in g 1

Printing in g 2

Printing in g 3

Panicking!

Defer in g 3

Defer in g 2

Defer in g 1

Defer in g 0

Recovered in f 4

Returned normally from f.

此外,利用defer来释放资源也不错

go
mu.Lock()
defer mu.Unlock()

指针

与C大部分一样,唯一与 C 不同:Go 没有指针运算。

与C差不多。

````````
go
type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	p := &v
	p.X = 1e9
	fmt.Println(v)
}
go
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 类型的结构体(指针)
)

数组

类型 [n]T 表示一个数组,它拥有 n 个类型为 T 的值。

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

	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}

数组的长度是其类型的一部分,因此数组不能改变大小。 这看起来是个限制,不过没关系,Go 拥有更加方便的使用数组的方式。

切片

````

a[low : high]

********

go
//这是一个数组字面量:

[3]bool{true, true, false}
//下面这样则会创建一个和上面相同的数组,然后再构建一个引用了它的切片:

[]bool{true, true, false}

切片的容量是从其实在数组的第一个元素开始数,到数组末尾的个数。

切片 s 的长度和容量可通过表达式 len(s)cap(s) 来获取。

你可以通过重新切片来扩展一个切片,给它提供足够的容量。

``
go
func main() {
	var s []int
	fmt.Println(s, len(s), cap(s))
	if s == nil {
		fmt.Println("nil!")
	}
}
/**
输出:
[] 0 0
nil!
*/

用 make 创建切片

切片可以用内置函数 make 来创建,这也是你创建动态数组的方式。make 函数会分配一个元素为零值的数组并返回一个引用了它的切片

go
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)
}
/*
对应输出:
a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
c len=2 cap=5 [0 0]
d len=3 cap=3 [0 0 0]
*/

切片的切片

切片可以包含任何类型,当然也包括其他切片。

go
	board := [][]string{
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
	}

追加

append 的第一个参数 s 是一个元素类型为 T 的切片,其余类型为 T 的值将会追加到该切片的末尾。结果是一个包含原切片所有元素加上新添加元素的切片。

当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。 返回的切片会指向这个新分配的数组。

go
func main() {
	var s []int
	printSlice(s)

	// 可在空切片上追加
	s = append(s, 0)
	printSlice(s)

	// 这个切片会按需增长
	s = append(s, 1)
	printSlice(s)

	// 可以一次性添加多个元素
	s = append(s, 2, 3, 4)
	printSlice(s)
}
/**
输出:
len=0 cap=0 []
len=1 cap=1 [0]
len=2 cap=2 [0 1]
len=5 cap=6 [0 1 2 3 4]
*/

range 遍历

for 循环的 range 形式可遍历切片或映射。

当使用 for 循环遍历切片时,每次迭代都会返回两个值。

第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本

go
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 i, _ := range pow

for _, value := range pow

若你只需要索引,忽略第二个变量即可。

for i := range pow

下划线加在导入的包名前,就会忽略导入的包中导出的东西,只执行包的init函数。

<font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">map</font>

````

<font style="color:rgb(51, 51, 51);background-color:rgb(250, 250, 250);">make</font>

go
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"])
}

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

若顶层类型只是一个类型名,那么你可以在字面量的元素中省略它。

go
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的CRUD

go
func main() {
	m := make(map[string]int)

	m["答案"] = 42
	fmt.Println("值:", m["答案"])

	m["答案"] = 48
	fmt.Println("值:", m["答案"])

	delete(m, "答案")
	fmt.Println("值:", m["答案"])

	v, ok := m["答案"]
	fmt.Println("值:", v, "是否存在?", ok)
}

****````````****
go
type Vertex struct {
	X, Y float64
}

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

func main() {
	v := Vertex{3, 4}
	fmt.Println(v.Abs())
}

go
type MyFloat float64

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

func main() {
	f := MyFloat(-math.Sqrt2)
	fmt.Println(f.Abs())
}