a tour of go 學習筆記

78
使用 A Tour of Go 線上教學 [email protected]

Upload: -

Post on 06-May-2015

748 views

Category:

Technology


0 download

DESCRIPTION

這是我自己依照 A Tour of Go 學習 Go 程式語言時的整理筆記。

TRANSCRIPT

Page 1: A Tour of Go 學習筆記

使用 A Tour of Go 線上教學

[email protected]

Page 2: A Tour of Go 學習筆記
Page 3: A Tour of Go 學習筆記

package main

import (

"fmt"

"math/rand"

)

func main() {

fmt.Println("My favorite number is", rand.Intn(10))

}

程式由 main package 執行

匯入要使用的 package

import "fmt"

import "math/rand"

也可寫成

Page 4: A Tour of Go 學習筆記

參數 說明

%f 用十進位小數表示浮點數

%e 用科學記號表示浮點數

%E 同上, 用大寫 E 表示科學記號

%g 取 %e 與 %f 中較簡短的結果

%G 取 %E 與 %f 中較簡短的結果

Page 5: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

func main() {

fmt.Println(math.Pi)

}

package 中大寫字首的名稱會自動公開給外部使用

Page 6: A Tour of Go 學習筆記
Page 7: A Tour of Go 學習筆記

package main

import "fmt"

func add(x int, y int) int {

return x + y

}

func main() {

fmt.Println(add(42, 13))

}

函式宣告

型別都在名稱之後

函式的傳回值型別一

樣是放在函式名稱後

Page 8: A Tour of Go 學習筆記

package main

import "fmt"

func add(x, y int) int {

return x + y

}

func main() {

fmt.Println(add(42, 13))

}

同時宣告兩個 int 型別的參數

Page 9: A Tour of Go 學習筆記

package main

import "fmt"

func swap(x, y string) (string, string)

{

return y, x

}

func main() {

a, b := swap("hello", "world")

fmt.Println(a, b)

}

傳回兩個值

Page 10: A Tour of Go 學習筆記

package main

import "fmt"

func split(sum int) (x, y int) {

x = sum * 4 / 9

y = sum - x

return

}

func main() {

fmt.Println(split(17))

}

具名的結果值參數

空的 return 會傳回具名結果值參數的目前值

Page 11: A Tour of Go 學習筆記

package main

import "fmt"

var i int

var c, python, java bool

func main() {

fmt.Println(i, c, python, java)

}

變數宣告 (型別一樣在名稱後面)

Page 12: A Tour of Go 學習筆記

package main

import "fmt"

var i, j int = 1, 2

var c, python, java = true, false, "no!"

func main() {

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

}

宣告時可直接設定初始值

有設定初值時可省略型別

Page 13: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

var i, j int = 1, 2

k := 3

c, python, java := true, false, "no!"

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

}

使用 := 可省略 var , 並依照初值自動選用型別

Page 14: A Tour of Go 學習筆記

package main

import (

"fmt"

"math/cmplx"

)

var (

ToBe bool = false

MaxInt uint64 = 1<<64 - 1

z complex128 = cmplx.Sqrt(-5 + 12i)

)

func main() {

const f = "%T(%v)\n"

fmt.Printf(f, ToBe, ToBe)

fmt.Printf(f, MaxInt, MaxInt)

fmt.Printf(f, z, z)

}

int8 int16 int32 int64

uint8 uint16 uint32 uint64

float32 float64

complex64 complex128

Page 15: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

func main() {

var x, y int = 3, 4

var f float64 = math.Sqrt(float64(3*3 + 4*4))

var z int = int(f)

fmt.Println(x, y, z)

}

T() 可轉型到 T

不同型別的運算一定要強制轉型

Page 16: A Tour of Go 學習筆記

package main

import "fmt"

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)

}

宣告常數

常數不能用 := 運算器

Page 17: A Tour of Go 學習筆記

package main

import "fmt"

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

}

常數會隨語境自動選用適當的型別如果執行 needInt(Big) 就會發生溢位

Page 18: A Tour of Go 學習筆記
Page 19: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

sum := 0

for i := 0; i < 10; i++ {

sum += i

}

fmt.Println(sum)

}

基本用法如同 C 中的 for

但要注意不用加括號

Page 20: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

sum := 1

for sum < 1000 {

sum += sum

}

fmt.Println(sum)

}

package main

import "fmt"

func main() {

sum := 1

for ; sum < 1000; {

sum += sum

}

fmt.Println(sum)

}

省略迴圈條件判斷前、後的敘述 此時連分號都可以省略

Page 21: A Tour of Go 學習筆記

package main

func main() {

for {

}

}

什麼都省略

Page 22: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

func sqrt(x float64) string {

if x < 0 {

return sqrt(-x) + "i"

}

return fmt.Sprint(math.Sqrt(x))

}

func main() {

fmt.Println(sqrt(2), sqrt(-4))

}

條件判斷式不用括號

一定要加大括號

Page 23: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

func pow(x, n, lim float64) float64 {

if v := math.Pow(x, n); v < lim {

return v

}

return lim

}

func main() {

fmt.Println(

pow(3, 2, 10),

pow(3, 3, 20),

)

}

條件判斷式不用括號

v 只在 if 區塊中有效

Page 24: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

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)

}

return lim

}

func main() {

fmt.Println(

pow(3, 2, 10),

pow(3, 3, 20),

)

}

v 在 else 區塊中也有效

Page 25: A Tour of Go 學習筆記

package main

import (

"fmt"

)

func Sqrt(x float64) float64 {

z := 1.0

for i := 0;i < 10;i++ {

z = z - (z*z - x)/(2*z)

}

return z

}

func main() {

fmt.Println(Sqrt(2))

}

Page 26: A Tour of Go 學習筆記

……

func Sqrt(x float64) (z float64,i int) {

z = 1.0

preZ := 0.0

for i = 0 ;math.Abs(z - preZ) > 0.000000001;i++ {

preZ = z

z = z - (z*z - x)/(2*z)

}

return

}

func main() {

fmt.Println(Sqrt(2))

}

Page 27: A Tour of Go 學習筆記
Page 28: A Tour of Go 學習筆記

package main

import "fmt"

type Vertex struct {

X int

Y int

}

func main() {

v := Vertex{1, 2}

v.X = 4

fmt.Println(v.X)

}

Vertex 是新的型別

每個 Vertex 資料是一個結構體

結構體就是一組資料欄位的集合

個別欄位使用 .運算器存取 結構體使用大括號設定初值

Page 29: A Tour of Go 學習筆記

package main

import "fmt"

type Vertex struct {

X int

Y int

}

func main() {

p := Vertex{1, 2}

q := &p

q.X = 1e9

fmt.Println(p)

}

可宣告指向結構體的指位器 使用指位器時會自動存取

(Transparent) 所指向的結構體, 所以沒有 C 的指位器運算

Page 30: A Tour of Go 學習筆記

package main

import "fmt"

type Vertex struct {

X, Y int

}

var (

p = Vertex{1, 2} // 以字面值建立 Vertex

q = &Vertex{1, 2} // 宣告指向 Vertex 的指位器r = Vertex{X: 1} // 只指定 x 初值, Y:0 用預設值

s = Vertex{} // X:0 與 Y:0 都是預設值)

func main() {

fmt.Println(p, q, r, s)

}

會顯示 &{1,2}

Page 31: A Tour of Go 學習筆記

package main

import "fmt"

type Vertex struct {

X, Y int

}

func main() {

v := new(Vertex)

fmt.Println(v) // &{0,0}

v.X, v.Y = 11, 9

fmt.Println(v) // &{11,9}

}

也可寫成 var v = new(Vertex)

Page 32: A Tour of Go 學習筆記
Page 33: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

var a [2]string

a[0] = "Hello"

a[1] = "World"

fmt.Println(a[0], a[1])

fmt.Println(a)

}

陣列長度要是常數不可更改不可設定初值

Page 34: A Tour of Go 學習筆記

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:])

}

從 p[1] 到 p[3]

p[1:1] -> []

p[1,2] -> [3]

以字面值建立

整數陣列

取得指向後面字面值陣列的切片

Page 35: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

a := make([]int, 5)

printSlice("a", a) // [0,0,0,0,0], len:5, cap:5

b := make([]int, 0, 5)

printSlice("b", b) // [], len:0, cap:5

c := b[:2]

printSlice("c", c) // [0,0], len:2, cap:5

d := c[2:5]

printSlice("d", d) // [0,0,0],len:3,cap:3

}

func printSlice(s string, x []int) {

fmt.Printf("%s len=%d cap=%d %v\n",

s, len(x), cap(x), x)

}

先建立 1 個含有 5 個 0 值的陣

列, 傳回指向此陣列所有元素的切片

先建立 1 個含有 5 個 0 值的陣

列, 傳回指向此陣列 0 個元素的切片

此 3 個切片都指向同一個陣列

切片起點到陣列最後元素的長度

切片本身的長度

Page 36: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

var z []int

fmt.Println(z, len(z), cap(z))// [],0,0

if z == nil {

fmt.Println("nil!")

}

}

沒有元素的切片

Page 37: A Tour of Go 學習筆記
Page 38: A Tour of Go 學習筆記

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)

}

} i 依序為 0,1,2,3,4…

v 依序為 1,2,4,8,16…

Page 39: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

pow := make([]int, 10)

for i := range pow {

pow[i] = 1 << uint(i)

}

for _, value := range pow {

fmt.Printf("%d\n", value)

}

}

省略元素變數只使用索引值

不需要索引變數時, 要寫 _

Page 40: A Tour of Go 學習筆記

package main

import "code.google.com/p/go-tour/pic"

func Pic(dx, dy int) [][]uint8 {

var pic = make([][]uint8,dy)

for i := 0;i < dy;i++ {

pic[i] = make([]uint8,dx)

}

for i:=0;i<dy;i++ {

for j:=0;j<dx;j++ {

pic[i][j] = uint8(i * j);

}

}

return pic

}

func main() {

pic.Show(Pic)

}

Page 41: A Tour of Go 學習筆記
Page 42: A Tour of Go 學習筆記

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

}

以字串為索引鍵、個別元素為 Vertex 的 map

map 一定要 make 才能用否則 m 為 nil, 無法設值

Page 43: A Tour of 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)

}

索引鍵:元素值

注意元素後要有逗號

用大括號括起來

Page 44: A Tour of Go 學習筆記

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)

}

個別元素設定時省略 型別名稱

Page 45: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

m := make(map[string]int)

m["Answer"] = 42 // 新增元素fmt.Println("The value:", m["Answer"])

m["Answer"] = 48 // 修改元素fmt.Println("The value:", m["Answer"])

delete(m, "Answer") // 刪除元素fmt.Println("The value:", m["Answer"])

v, ok := m["Answer"] // 讀取元素, 元素存在時 ok 為 true

fmt.Println("The value:", v, "Present?", ok)

}

Page 46: A Tour of Go 學習筆記

package main

import (

"code.google.com/p/go-tour/wc"

"strings"

)

func WordCount(s string) map[string]int {

wc := make(map[string]int)

for _,w := range strings.Fields(s) {

wc[w] = wc[w] + 1;

}

return wc

}

func main() {

wc.Test(WordCount)

}

Page 47: A Tour of Go 學習筆記
Page 48: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

func main() {

hypot := func(x, y float64) float64 {

return math.Sqrt(x*x + y*y)

}

fmt.Println(hypot(3, 4))

}

將定義好的函式設定給變數

Page 49: A Tour of Go 學習筆記

package main

import "fmt"

func adder() func(int) int {

sum := 0

return func(x int) int {

sum += x

return sum

}

}

叫用 adder 會把當時的 sum

變數封裝一份到傳回的函式中

func main() {

pos, neg := adder(), adder()

for i := 0; i < 10; i++ {

fmt.Println(

pos(i),

neg(-2*i),

)

}

}

pos 與 neg 各自擁有一份專屬的 sum 變數

Page 50: A Tour of Go 學習筆記

package main

import "fmt"

func fibonacci() func() int {

now, next := 0,1

return func() int {

now, next = next, now + next

return now

}

}

func main() {

f := fibonacci()

for i := 0; i < 10; i++ {

fmt.Println(f())

}

}

Page 51: A Tour of Go 學習筆記
Page 52: A Tour of Go 學習筆記

package main

import (

"fmt"

"runtime"

)

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)

}

}

前置處理

Page 53: A Tour of Go 學習筆記

……

func main() {

fmt.Println("When's Saturday?")

today := time.Now().Weekday()

switch time.Saturday {

case today + 0:

fmt.Println("Today.")

case today + 1:

fmt.Println("Tomorrow.")

case today + 2:

fmt.Println("In two days.")

default:

fmt.Println("Too far away.")

}

}

不用 break

Page 54: A Tour of Go 學習筆記

package main

import (

"fmt"

"time"

)

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.")

}

}

沒有用來當判斷條件的變數

Page 55: A Tour of Go 學習筆記

package main

import (

"fmt"

"math/cmplx"

)

func Cbrt(x complex128) complex128 {

z := 1 + 0i

for i:= 0;i<10;i++ {

z = z - (z * z *z - x)/(3 * z * z)

}

return z

}

func main() {

fmt.Println(Cbrt(2))

fmt.Println(cmplx.Pow(2, 1.0/3)) // 驗證是否正確?}

記得要用浮點數

Page 56: A Tour of Go 學習筆記
Page 57: A Tour of Go 學習筆記

package main

import (

"fmt"

"math"

)

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

}

為 Vertex 定義方法

叫用 Vertex 的方法

Page 58: A Tour of 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())

}

為 Vertex 定義方法

叫用 MyFloat 的方法

Page 59: A Tour of Go 學習筆記

……

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}

v.Scale(5)

fmt.Println(v, v.Abs()) // &{15, 20}, 25

}

以指標形式為 Vertex 定義方法

會修改到 v 的內容

v 是指標, 所以會修改到 v 所指向的結構體

Page 60: A Tour of Go 學習筆記

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)

}

……

type Abser interface {

Abs() float64

}

func main() {

var a Abser

f := MyFloat(-math.Sqrt2)

v := Vertex{3, 4}

a = f // MyFloat 是 Abser

a = &v // *Vertex 是 Abser

a = v // Vertex 不是 Abser

fmt.Println(a.Abs())

}

type MyFloat float64

無法成功編譯

相符的方法

Page 61: A Tour of Go 學習筆記

package main

import (

"fmt"

"os"

)

type Reader interface {

Read(b []byte) (

n int, err error)

}

type Writer interface {

Write(b []byte) (

n int, err error)

}

type ReadWriter interface {

Reader

Writer

}

func main() {

var w Writer

// os.Stdout implements Writer

w = os.Stdout

fmt.Fprintf(w, "hello, writer\n")

}

實作介面並不需要任何宣告

實作介面的型別和介面定義所在的 package

不同, 兩者完全不相依賴, 可更正確定義抽象化的介面

Page 62: A Tour of Go 學習筆記

func run() error {

return &MyError{

time.Now(),

"it didn't work",

}

}

func main() {

if err := run(); err != nil {

fmt.Println(err)

}

}

package main

import (

"fmt"

"time"

)

type MyError struct {

When time.Time

What string

}

func (e *MyError) Error()

string {

return fmt.Sprintf(

"at %v, %s",

e.When, e.What)

}

實作了內建的

Println 遇到 error 介面時會自動叫用介面中的 Error() 方法

type error interface {

Error() string

}

Page 63: A Tour of Go 學習筆記

func Sqrt(f float64) (

float64, error) {

if f >= 0 {

z := 1.0

for i := 0;i < 10;i++ {

z = z –

(z*z - f)/(2*z)

}

return z, nil

}

var e ErrNegativeSqrt =

ErrNegativeSqrt(f)

return 0, e

}

package main

import "fmt"

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt)

Error() string {

return fmt.Sprintf(

"無法求 %f 的平方根", e)

}

func main() {

fmt.Println(Sqrt(2))

fmt.Println(Sqrt(-2))

}

實作 error 介面

傳回 error 介面

Page 64: A Tour of Go 學習筆記

http package

Page 65: A Tour of Go 學習筆記

package main

import (

"fmt"

"net/http"

)

type Hello struct{}

func (h Hello) ServeHTTP(

w http.ResponseWriter,

r *http.Request) {

fmt.Fprint(w, "Hello!")

}

func main() {

var h Hello

http.ListenAndServe("localhost:4000", h)

}

實作 net/http package中所定義的 Handler 介面

type Handler interface {

ServeHTTP(

w ResponseWriter,

r *Request)

}

Page 66: A Tour of Go 學習筆記

func (s *Struct) ServeHTTP(

w http.ResponseWriter,

r *http.Request) {

fmt.Fprint(w,

s.Greeting+s.Punct+s.Who)

}

func main() {

http.Handle("/string",

String("I'm a frayed knot."))

http.Handle("/struct",

&Struct{"Hello", ":",

"Gophers!"})

http.ListenAndServe(

"localhost:4000", nil)

}

package main

import "net/http"

import "fmt"

type String string

type Struct struct {

Greeting string

Punct string

Who string

}

func (s String) ServeHTTP(

w http.ResponseWriter,

r *http.Request) {

fmt.Fprint(w, s)

}

實作 Handler 介面

註冊處理路徑 已註冊處理個別路徑不需再提供 Handler

Page 67: A Tour of Go 學習筆記
Page 68: A Tour of Go 學習筆記

package main

import (

"fmt"

"image"

)

func main() {

m := image.NewRGBA(image.Rect(0, 0, 100, 100))

fmt.Println(m.Bounds())

fmt.Println(m.At(0, 0).RGBA())

}

實作有 image 中所定義的 Image 介面

type Image interface {

ColorModel() color.Model

Bounds() Rectangle

At(x, y int) color.Color

}

Page 69: A Tour of Go 學習筆記

package main

import (

"code.google.com/p/go-tour/pic"

"image"

"image/color"

)

type Image struct{}

func (i Image) ColorModel()

color.Model {

return color.RGBAModel

}

func (i Image) Bounds()

image.Rectangle {

return image.Rect(0,0,200,200)

}

func (i Image) At(x, y int)

color.Color {

v := uint8(x * y)

return color.RGBA{

v, v, 255, 255

}

}

func main() {

m := Image{}

pic.ShowImage(m)

}

實作 Image 介面

Page 70: A Tour of Go 學習筆記

package main

import (

"io"

"os"

"strings"

)

type rot13Reader struct {

r io.Reader

}

func main() {

s := strings.NewReader(

"Lbh penpxrq gur pbqr!")

r := rot13Reader{s}

io.Copy(os.Stdout, &r)

}

func (rot rot13Reader)

Read(p []byte)(n int, e error) {

n,e = rot.r.Read(p)

if n > 0 {

for i := 0;i < n;i++ {

switch {

case p[i] <= 'M':

p[i] += 13

case p[i] <= 'Z':

p[i] -= 13;

case p[i] <= 'm':

p[i] += 13

case p[i] <= 'z':

p[i] -= 13;

}

}

}

return n,e

}

實作 Reader 介面

Page 71: A Tour of Go 學習筆記
Page 72: A Tour of Go 學習筆記

package main

import (

"fmt"

"time"

)

func say(s string) {

for i := 0; i < 5; i++ {

ain(time.Sleep(100 * time.Millisecond)

fmt.Println(s)

}

}

func m) {

go say("world")

say("hello")

} 以另一個執行緒執行 say

hello

world

hello

world

hello

world

hello

world

hello

執行結果 (咦?少個 world?)

Page 73: A Tour of Go 學習筆記

func main() {

a := []int{7, 2, 8, -9, 4, 0}

c := make(chan int)

go sum(a[:len(a)/2], c)

go sum(a[len(a)/2:], c)

x, y := <-c, <-c

fmt.Println(x, y, x+y)

}

package main

import "fmt"

func sum(a []int,

c chan int) {

sum := 0

for _, v := range a {

sum += v

}

c <- sum // send sum to c

}

① 建立傳遞int 的通道

③ 等待通道有空位後將加總值傳入通道

④ 等待通道有資料後一一取出加總值

② 提供通道給 gotoutine

Page 74: A Tour of Go 學習筆記

package main

import "fmt"

func main() {

c := make(chan int, 2)

c <- 1

c <- 2

fmt.Println(<-c)

fmt.Println(<-c)

}

設定通道暫存區大小

等待通道中有資料時讀取等待通道有空位時送入資料

Page 75: A Tour of Go 學習筆記

func main() {

c := make(chan int, 10)

go fibonacci(cap(c), c)

for i := range c {

fmt.Println(i)

}

}

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)

}

從通道依序取出資料, 直到通道清空且傳送端關閉通道

只有傳送端可以關閉通道若通道清空且傳送端關閉通道時 ok 為 false

v, ok := <-ch

Page 76: A Tour of Go 學習筆記

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)

}

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

}

}

}

專門用在通訊的 switch

多個 case 同時成立時會隨機挑選執行

Page 77: A Tour of Go 學習筆記

……

import "fmt"

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

return

default:

fmt.Println(" .")

time.Sleep(50 * time.Millisecond)

}

}

}

沒有可用通道時執行

在此區塊嘗試從 tick 或是 boom

通道讀取資料就會進入等待狀態

Page 78: A Tour of Go 學習筆記

func Same(t1, t2 *tree.Tree) bool {

ch1 := make(chan int)

ch2 := make(chan int)

go Walk(t1,ch1)

go Walk(t2,ch2)

for i := 0;i <10;i++ {

if <-ch1 != <-ch2 {

return false

}

}

return true

}

func main() {

fmt.Println(Same(

tree.New(1),

tree.New(1)))

}

package main

import (

"code.google.com/p/go-

tour/tree"

"fmt"

)

func Walk(t *tree.Tree,

ch chan int) {

if t != nil {

Walk(t.Left, ch)

ch <- t.Value

Walk(t.Right, ch)

} else {

return

}

}