GO
``package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("我最喜欢的数字是 ", rand.Intn(10))
}
****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
}
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>
var i, j int = 1, 2
func main() {
var c, python, java = true, false, "no!"
fmt.Println(i, j, c, python, java)
}
````****``````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>
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名
// 表示一个 Unicode 码位
float32 float64
complex64 complex128
****- ``
- ``
- ``
``````var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
i := 42
f := float64(i)
u := uint(f)
````var i int
j := i // j 也是一个 int
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
````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)
}
****``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>
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 {
}
`````` 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>
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("很多天后。")
}
`````` switch {
case t.Hour() < 12:
fmt.Println("早上好!")
case t.Hour() < 17:
fmt.Println("下午好!")
default:
fmt.Println("晚上好!")
}
把这个调用函数推入一个栈中,这个函数return后再LIFO地调用它声明的defer。这导致其执行是可预测的。func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
panic类似于Exception或者error,发生时会逐层退出函数栈,但是退出函数时又可以触发已存储的defer函数
recover类似于catch的作用,但是仅能在defer函数内部使用,可捕获传递上来的错误并阻止冒泡
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来释放资源也不错
mu.Lock()
defer mu.Unlock()
指针
与C大部分一样,唯一与 C 不同:Go 没有指针运算。
与C差不多。
````````type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
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 的值。
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]
********
//这是一个数组字面量:
[3]bool{true, true, false}
//下面这样则会创建一个和上面相同的数组,然后再构建一个引用了它的切片:
[]bool{true, true, false}
切片的容量是从其实在数组的第一个元素开始数,到数组末尾的个数。
切片 s 的长度和容量可通过表达式 len(s)
和 cap(s)
来获取。
你可以通过重新切片来扩展一个切片,给它提供足够的容量。
``func main() {
var s []int
fmt.Println(s, len(s), cap(s))
if s == nil {
fmt.Println("nil!")
}
}
/**
输出:
[] 0 0
nil!
*/
用 make 创建切片
切片可以用内置函数 make 来创建,这也是你创建动态数组的方式。make 函数会分配一个元素为零值的数组并返回一个引用了它的切片
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]
*/
切片的切片
切片可以包含任何类型,当然也包括其他切片。
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
追加
append 的第一个参数 s 是一个元素类型为 T 的切片,其余类型为 T 的值将会追加到该切片的末尾。结果是一个包含原切片所有元素加上新添加元素的切片。
当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。 返回的切片会指向这个新分配的数组。
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 循环遍历切片时,每次迭代都会返回两个值。
第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。
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>
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"])
}
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)
}
若顶层类型只是一个类型名,那么你可以在字面量的元素中省略它。
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
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)
}
****````````****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())
}
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())
}