Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

[A Tour of Go 學習筆記] 06 Range、Map 和 function

使用官方教學瞭解 Go Range、Map 和 function

Ray

初入 Golang 的世界,首先我們使用官方教學:A Tour of Go 來認識基本的 Golang 使用
這篇介紹 Range、Map 和 function

Range

用 for 迴圈的range形式可以遍歷切片或是 map,類似於其他語言的 foreach 用法
當使用 for 迴圈遍歷切片的時候,每次迭代都會回傳兩個值。第一個值是元素的 index,第二個值是元素內容的副本。

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)
	}
}
/*
>>> 2**0 = 1
>>> 2**1 = 2
>>> 2**2 = 4
>>> 2**3 = 8
>>> 2**4 = 16
>>> 2**5 = 32
>>> 2**6 = 64
>>> 2**7 = 128
*/

如果不需要某個值(通常是 index)可以用_來忽略他
因為 golang 對定義卻沒用的變數很在意,會出錯誤:key declared but not used

for i, _ := range pow
for _, value := range pow

如果只需要 index,可以直接忽略第二個變數

for i := range pow

底下是一個只取 index 的範例:

package main

import "fmt"

func main() {
	pow := make([]int, 10)
	for i := range pow {
		pow[i] = 1 << uint(i) // 把值設為 index 左移一位元,等於 2 的 i 次方
	}
	for _, value := range pow {
		fmt.Printf("%d\n", value)
	}
}
/*
>>> 1
>>> 2
>>> 4
>>> 8
>>> 16
>>> 32
>>> 64
>>> 128
>>> 256
>>> 512
*/

Map

前面介紹的不管是陣列或是切片,都是以數字當 index,而 map 可以使用字串作為 index
用在Key-Value的組合

在初始化沒有賦值時 map 的初始值(zero value)是nil,一個nil map 沒有 key 也不能加入 key
使用make函數可以初始化指定型別 map 並回傳

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"])
}
/*
>>> {40.68433 -74.39967}
*/

map 和 struct 類似,但是 key 是必須的

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)
}
/*
>>> map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
*/

如果最頂層的型別只是一種類別名稱,則可以省略不寫

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)
}
/*
>>> map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
*/

修改 map 中的值

在 map 中插入或修改元素

m[key] = elem

取得元素

elem = m[key]

刪除元素

delete(m, key)

透過雙賦值(two-value assignment)檢查某個鍵值是否存在

elem, ok = m[key]

如果 key 存在 m 中ok = true,否則ok = false
若讀取不存在的鍵值時,會得到 map 的元素類型的預設值
在使用時若elem或是ok還沒被定義,可以使用:做簡短變數聲明

elem, ok := m[key]

實際操作起來就:

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"]
	fmt.Println("The value:", v, "Present?", ok)
}
/*
>>> The value: 42
>>> The value: 48
>>> The value: 0
>>> The value: 0 Present? false
*/

函數 Function

Function values

function 也是值,也可以被傳遞
函數可以作為函數的參數或是回傳值

package main

import (
	"fmt"
	"math"
)

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))
}
/*
>>> 13
>>> 5
>>> 81
*/

閉包 Function closures

Go function 也可以是一個閉包
閉包是一個函數值,引用了函數本身外部的變數。閉包函數被指定給變數,並且可以存取變數。
換句話說,閉包函數跟變數被「綁定」在一起。

範例中的adder這個 function 回傳一個閉包,所以每個sum變數都擁有自己的閉包函數

package main

import "fmt"

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}
/*
>>> 0 0
>>> 1 -2
>>> 3 -6
>>> 6 -12
>>> 10 -20
>>> 15 -30
>>> 21 -42
>>> 28 -56
>>> 36 -72
>>> 45 -90
*/

最新文章

Category

Tag