|
// Basic function |
|
|
|
package main |
|
|
|
import "fmt" |
|
|
|
func add(x, y int) int { |
|
return x + y |
|
} |
|
|
|
func main() { |
|
fmt.Println(add(42, 13)) |
|
} |
|
|
|
|
|
// Multivalue Return |
|
|
|
func swap(x, y string) (string, string) { |
|
return y, x |
|
} |
|
|
|
// Named returns |
|
|
|
func split(sum int) (x, y int) { |
|
x = sum * 4 / 9 |
|
y = sum - x |
|
return |
|
} |
|
|
|
// Variables |
|
|
|
|
|
var c, python, java bool // package scope |
|
|
|
func main() { |
|
var i int // function scope |
|
} |
|
|
|
|
|
// Variable initialize |
|
|
|
var i, j int = 1, 2 |
|
var c, java = true, "no!" // extract type from initial value |
|
python := false |
|
|
|
|
|
// Basic types |
|
|
|
bool |
|
string |
|
int int8 int16 int32 int64 |
|
uint uint8 uint16 uint32 uint64 uintptr |
|
byte // == uint8 |
|
rune // == int32 表示一个 Unicode 码点 |
|
float32 float64 |
|
complex64 complex128 |
|
|
|
|
|
// Define in batch |
|
|
|
var ( |
|
ToBe bool = false |
|
MaxInt uint64 = 1<<64 - 1 |
|
z complex128 = cmplx.Sqrt(-5 + 12i) |
|
) |
|
|
|
const f = "%T(%v)\n" |
|
|
|
// Zero value |
|
|
|
没有明确初始值的变量声明会被赋予它们的 零值 。 |
|
零值是: |
|
• 数值类型为 0 , |
|
• 布尔类型为 false , |
|
• 字符串为 "" (空字符串)。 |
|
|
|
|
|
// Constants |
|
|
|
const Pi = 3.14 |
|
|
|
const ( |
|
Big = 1 << 100 |
|
Small = Big >> 99 |
|
) |
|
|
|
// similar to #define rather than const x = 123 |
|
|
|
|
|
// Loop (only for loop in Go) |
|
|
|
|
|
func main() { |
|
sum := 0 |
|
for i := 0; i < 10; i++ { |
|
sum += i |
|
} |
|
} |
|
|
|
|
|
func main() { |
|
sum := 1 |
|
for sum < 1000 { // equals to "for ; sum < 1000;" |
|
sum += sum |
|
} |
|
} |
|
|
|
|
|
|
|
// If statement |
|
|
|
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 |
|
} |
|
|
|
|
|
// Switch Statement |
|
|
|
func main() { |
|
fmt.Print("Go runs on ") |
|
switch os := runtime.GOOS; os { // 2 subclauses |
|
case "darwin": |
|
fmt.Println("OS X.") |
|
case "linux": |
|
fmt.Println("Linux.") |
|
default: |
|
// freebsd, openbsd, |
|
// plan9, windows... |
|
fmt.Printf("%s.", os) |
|
} |
|
} |
|
|
|
除非以 fallthrough 语句结束,否则分支会自动终止。 |
|
switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。 |
|
|
|
|
|
// Defer |
|
|
|
func main() { |
|
defer fmt.Println("world") |
|
|
|
fmt.Println("hello") |
|
} |
|
|
|
推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。 |
|
|
|
|
|
// Pointer |
|
|
|
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 |
|
} |
|
|
|
与 C 不同,Go 没有指针运算。 |
|
|
|
|
|
// Struct |
|
|
|
type Vertex struct { |
|
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(Vertex{1, 2}) |
|
v.X = 4 |
|
fmt.Println(v.X) |
|
p := &v // pointer to struct |
|
p.X = 1e9 // same with "->" in C |
|
} |
|
|
|
|
|
// Arrays |
|
|
|
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) |
|
} |
|
|
|
|
|
// Slices |
|
|
|
func main() { |
|
primes := [6]int{2, 3, 5, 7, 11, 13} |
|
|
|
var s []int = primes[1:4] |
|
fmt.Println(s) |
|
} |
|
|
|
每个数组的大小都是固定的。 而切片则为数组元素提供动态大小的、灵活的视角。 在实践中,切片比数组更常用。 |
|
切片并不存储任何数据, 它只是描述了底层数组中的一段。更改切片的元素会修改其底层数组中对应的元素。 |
|
r := []bool{true, false, true, true, false, true} //下面这样则会创建一个数组,然后构建一个引用了它的切片 |
|
|
|
|
|
// Create Slice with Make statement |
|
|
|
x := make([]int, 0, 5) |
|
fmt.Printf("len=%d cap=%d %v\n", len(x), cap(x), x) |
|
//b len=0 cap=5 [] |
|
|
|
|
|
// Append elements to slice |
|
|
|
var s []int // nil [] |
|
s = append(s, 1) // allocate [1] |
|
s = append(s, 2, 3, 4) // reallocate because cap(s) < len(s) + 3 : [1,2,3,4] |
|
|
|
|
|
// Range |
|
|
|
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 _, value := range pow { // if not need index |
|
fmt.Printf("%d\n", value) |
|
} |
|
} |
|
|
|
|
|
// Maps |
|
|
|
m = make(map[string]Vertex) |
|
m["Bell Labs"] = Vertex{ |
|
40.68433, -74.39967, |
|
} |
|
fmt.Println(m["Bell Labs"]) |
|
|
|
映射的零值为 nil 。`nil` 映射既没有键,也不能添加键。 |
|
|
|
|
|
type Vertex struct { |
|
Lat, Long float64 |
|
} |
|
|
|
var m = map[string]Vertex{ |
|
"Bell Labs": {40.68433, -74.39967}, |
|
"Google": {37.42202, -122.08408}, |
|
} |
|
|
|
|
|
// Modify Maps |
|
|
|
m := make(map[string]int) |
|
|
|
m["Answer"] = 42 // create |
|
fmt.Println("The value:", m["Answer"]) |
|
|
|
m["Answer"] = 48 // update |
|
fmt.Println("The value:", m["Answer"]) |
|
|
|
delete(m, "Answer") // remove |
|
fmt.Println("The value:", m["Answer"]) |
|
|
|
v, ok := m["Answer"] // get value and check |
|
fmt.Println("The value:", v, "Present?", ok) |
|
|
|
|
|
// Function values |
|
|
|
|
|
func compute(fn func(float64, float64) float64) float64 { |
|
return fn(3, 4) |
|
} |
|
|
|
func main() { |
|
hypot := func(x, y float64) float64 { |
|
return math.Sqrt(x*x + y*y) |
|
} |
|
fmt.Println(hypot(5, 12)) |
|
|
|
fmt.Println(compute(hypot)) |
|
fmt.Println(compute(math.Pow)) |
|
} |
|
|
|
// Method |
|
|
|
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()) |
|
} |
|
|
|
|
|
// Pointer recevier |
|
|
|
func (v Vertex) Abs() float64 { |
|
return math.Sqrt(v.X*v.X + v.Y*v.Y) |
|
} |
|
|
|
func (v *Vertex) Scale(f float64) { |
|
v.X = v.X * f |
|
v.Y = v.Y * f |
|
} |
|
|
|
|
|
// Interface |
|
|
|
type I interface { |
|
M() |
|
} |
|
|
|
type T struct { |
|
S string |
|
} |
|
|
|
func (t *T) M() { |
|
if t == nil { // t can be nil |
|
fmt.Println("<nil>") |
|
return |
|
} |
|
fmt.Println(t.S) |
|
} |
|
|
|
func main() { |
|
var i I |
|
|
|
var t *T |
|
i = t |
|
describe(i) |
|
i.M() |
|
|
|
i = &T{"hello"} |
|
describe(i) |
|
i.M() |
|
} |
|
|
|
func describe(i I) { |
|
fmt.Printf("(%v, %T)\n", i, i) |
|
} |
|
|
|
|
|
// Empty Interface |
|
|
|
func main() { |
|
var i interface{} |
|
describe(i) |
|
|
|
i = 42 |
|
describe(i) |
|
|
|
i = "hello" |
|
describe(i) |
|
} |
|
|
|
func describe(i interface{}) { |
|
fmt.Printf("(%v, %T)\n", i, i) |
|
} |
|
|
|
|
|
// Type Assertion |
|
|
|
s := i.(string) |
|
s, ok := i.(string) |
|
|
|
|
|
// Type Switch |
|
|
|
switch v := i.(type) { // only in switch statement |
|
case T: |
|
// v 的类型为 T |
|
case S: |
|
// v 的类型为 S |
|
default: |
|
// 没有匹配,v 与 i 的类型相同 |
|
} |
|
|
|
|
|
// interface Stringer |
|
|
|
type Person struct { |
|
Name string |
|
Age int |
|
} |
|
|
|
func (p Person) String() string { |
|
return fmt.Sprintf("%v (%v years)", p.Name, p.Age) |
|
} |
|
|
|
|
|
// Error (interface) |
|
|
|
type MyError struct { |
|
When time.Time |
|
What string |
|
} |
|
|
|
func (e *MyError) Error() string { |
|
return fmt.Sprintf("at %v, %s", |
|
e.When, e.What) |
|
} |
|
|
|
func run() error { |
|
return &MyError{ |
|
time.Now(), |
|
"it didn't work", |
|
} |
|
} |
|
|
|
func main() { |
|
if err := run(); err != nil { |
|
fmt.Println(err) |
|
} |
|
} |
|
|
|
|
|
// Reader (interface) |
|
|
|
func main() { |
|
r := strings.NewReader("Hello, Reader!") |
|
|
|
b := make([]byte, 8) |
|
for { |
|
n, err := r.Read(b) |
|
fmt.Printf("n = %v err = %v b = %v\n", n, err, b) |
|
fmt.Printf("b[:n] = %q\n", b[:n]) |
|
if err == io.EOF { |
|
break |
|
} |
|
} |
|
} |
|
|
|
|
|
io.Reader 接口有一个 Read 方法: |
|
func (T) Read(b []byte) (n int, err error) |
|
|
|
|
|
// Go Routine |
|
|
|
func main() { |
|
go say("world") |
|
say("hello") |
|
} |
|
|
|
|
|
// Channel |
|
|
|
ch := make(chan int) |
|
ch <- 2 |
|
fmt.Println(<-ch) |
|
|
|
|
|
// Channel with buffer |
|
|
|
ch := make(chan int, 2) |
|
ch <- 1 |
|
ch <- 2 |
|
fmt.Println(<-ch) |
|
fmt.Println(<-ch) |
|
|
|
|
|
// range and close for channel |
|
|
|
func fibonacci(n int, c chan int) { |
|
x, y := 0, 1 |
|
for i := 0; i < n; i++ { |
|
c <- x |
|
x, y = y, x+y |
|
} |
|
close(c) |
|
} |
|
|
|
func main() { |
|
c := make(chan int, 10) |
|
go fibonacci(cap(c), c) |
|
for i := range c { |
|
fmt.Println(i) |
|
} |
|
} |
|
|
|
信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有值需要发送的时候才有必要关闭,例如终止一个 range 循环。 |
|
|
|
|
|
// select statement |
|
|
|
func fibonacci(c, quit chan int) { |
|
x, y := 0, 1 |
|
for { |
|
select { |
|
case c <- x: |
|
x, y = y, x+y |
|
case <-quit: |
|
fmt.Println("quit") |
|
return |
|
default: |
|
fmt.Print(".") |
|
time.Sleep(100 * time.Millisecond) |
|
} |
|
} |
|
} |
|
|
|
func main() { |
|
c := make(chan int) |
|
quit := make(chan int) |
|
go func() { |
|
for i := 0; i < 10; i++ { |
|
fmt.Println(<-c) |
|
} |
|
quit <- 0 |
|
}() |
|
fibonacci(c, quit) |
|
} |