package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)\n", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
package main
import "fmt"
type IPAddr [4]byte
// TODO: Add a "String() string" method to IPAddr.
func (p IPAddr) String() string {
return fmt.Sprintf("%d.%d.%d.%d", p[0], p[1], p[2], p[3])
}
func main() {
addrs := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
for n, a := range addrs {
fmt.Printf("%v: %v\n", n, a)
}
}
package main
import "fmt"
func test1() {
fmt.Println("test1 ------------------")
s := []int{2, 3, 5, 7, 11, 13}
printSlice("s", s)
printSlice("s[1:4]", s[1:4])
printSlice("s[:3]", s[:3])
printSlice("s[4:]", s[4:])
a := s[2:5]
printSlice("a", a)
a[0] = 100
printSlice("a", a)
printSlice("s", s)
}
func test2() {
fmt.Println("test2 ------------------")
var arr [10]int
for i := 0; i < 10; i++ {
arr[i] = i
}
arrS := arr[:]
fmt.Println(arr)
printSlice("arrS", arrS)
arrS[0] = 100
fmt.Println(arr)
printSlice("arrS", arrS)
}
func test3() {
fmt.Println("test3 ------------------")
a := make([]int, 5)
printSlice("a", a)
//b := make([]int, 0, 5)
b := make([]int, 5, 5) //change len to 5, you will know why.
printSlice("b", b)
c := b[:2]
printSlice("c", c)
d := c[2:5]
printSlice("d", d)
c[0] = 200
fmt.Println("-------------")
printSlice("a", a)
printSlice("b", b)
printSlice("c", c)
printSlice("d", d)
d[0] = 100
fmt.Println("-------------")
printSlice("a", a)
printSlice("b", b)
printSlice("c", c)
printSlice("d", d)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n",
s, len(x), cap(x), x)
}
func main() {
test1()
test2()
test3()
}
select 语句使得一个 goroutine 在多个通讯操作上等待。
select 会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个条件分支。当多个都准备好的时候,会随机选择一个。
package main
import "fmt"
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
}
}
}
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)
}
当 select 中的其他条件分支都没有准备好的时候,default 分支会被执行。
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
发送者可以 close 一个 channel 来表示再没有值会被发送了。接收者可以通过赋值语句的第二参数来测试 channel 是否被关闭:当没有值可以接收并且 channel 已经被关闭,那么经过
v, ok := <-ch
之后 ok 会被设置为 false。
循环 for i := range c
会不断从 channel 接收值,直到它被关闭。
注意: 只有发送者才能关闭 channel,而不是接收者。向一个已经关闭的 channel 发送数据会引起 panic。 还要注意: channel 与文件不同;通常情况下无需关闭它们。只有在需要告诉接收者没有更多的数据的时候才有必要进行关闭,例如中断一个 range。
package main
import "fmt"
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)
}
}
package main
import (
"fmt"
"sync"
"time"
)
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
c.v[key]++
c.mux.Unlock()
}
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}
方法可以与命名类型或命名类型的指针关联。
刚刚看到的两个 Abs 方法。一个是在 *Vertex 指针类型上,而另一个在 MyFloat 值类型上。 有两个原因需要使用指针接收者。首先避免在每个方法调用中拷贝值(如果值类型是大的结构体的话会更有效率)。其次,方法可以修改接收者指向的值。
尝试修改 Abs 的定义,同时 Scale 方法使用 Vertex 代替 *Vertex 作为接收者。
当 v 是 Vertex 的时候 Scale 方法没有任何作用。Scale 修改 v。当 v 是一个值(非指针),方法看到的是 Vertex 的副本,并且无法修改原始值。
Abs 的工作方式是一样的。只不过,仅仅读取 v。所以读取的是原始值(通过指针)还是那个值的副本并没有关系。
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}
输出:
Before scaling: &{X:3 Y:4}, Abs: 5
After scaling: &{X:15 Y:20}, Abs: 25
如果去掉指针,则输出:
Before scaling: &{X:3 Y:4}, Abs: 5
After scaling: &{X:3 Y:4}, Abs: 5
但是下面这种情况,没有指针的函数,居然修改也有效,就是Swap这个函数
package main
import (
"fmt"
)
type Point struct {
a, b int
}
type intPairs []Point
// IntPairs compare on a only.
func (d intPairs) Len() int { return len(d) }
func (d intPairs) Less(i, j int) bool { return d[i].a < d[j].a }
func (d intPairs) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func main() {
var d intPairs
p1 := Point{1, 2}
p2 := Point{3, 4}
p3 := Point{5, 6}
d = append(d, p1)
d = append(d, p2)
d = append(d, p3)
fmt.Println(d)
d.Swap(1, 2)
fmt.Println(d)
}
输出:
[{1 2} {3 4} {5 6}]
[{1 2} {5 6} {3 4}]