iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 5
1
Software Development

Go繁不及備載系列 第 5

# Day05 開寫程式Go ,變數宣告前方小坑

Day05 開寫程式Go,變數宣告前方小坑


開寫程式"蛤螺握德"

新增一個helloWorld資料夾,裡面創建main.go檔案。

package main

import "fmt"

func main()  {
	fmt.Println("Hello World!!")
}

ㄝ? 圖中ㄉ資料夾不符 請無視
helloWorld

執行

寫完存檔後,到helloWorld資料夾裡下

$ go run main.go  

這一行的效果等於以下兩行

$ go build main.go 編譯出一個執行檔
$ ./main.exe 接著執行它

(但 go run 產生的執行檔是在電腦的暫存區/tmp下)

或者用Goland IDE,直接按預設快捷鍵

Ctrl + Shift + F10(for windows)  
Ctrl + Shift + R(for Mac)  

編譯&執行


【變數宣告】

變數宣告了就要使用, 否則會出現variable declared and not used的錯誤。
除非變數的名稱為_

var Name Type = Expression

var a int = 16

要嘛省略型別 Type,由Expression決定Type
要嘛省略表達式 Expression,變數值為 Type初始值(零值)
初始值(零值):0, false, "", nil 等等

https://play.golang.org/p/MnmDT24cMTQ

func main()  {
	var a = 16
	var b int
	var _ = 10
	fmt.Println(a, b)
}
// result:
// 16 0

短變數宣告(用:= 代替var)

短變數宣告(Short variable declarations)

Name := Expression

a := 10

宣告declare(:=) 跟 指派assign(=)是不同的,
一次宣告多個變數,若已宣告過的變數會自動變成assign效果

宣告多個變數

https://play.golang.org/p/cy6L6tKz01n

func main()  {
	var b int = 123
	a, b := 100, 99
	c, b := 0, 1
	fmt.Println(a, b, c)
}

// result:
// 100 1 0

短變數宣告 (:=) 方法簡便,
常用在宣告初始化大量、生命週期短的區域變數(就是迴圈內的i, j啦);
反之,var 則常用在明確設定型別、生命週期較長的變數。

【前方坑洞注意】-宣告區域變數

坑A範例
https://play.golang.org/p/1aI9NdAdrQ_T

package main

import "fmt"

var a = "Hello!"

func main()  {
	b := 10
	fmt.Println(&a, a, &b, b)

	a, b := 100, 99
	fmt.Println(&a, a, &b, b)
}

/* result:
0x54dc50 Hello! 0xc00002c008 10
0xc00002c048 100 0xc00002c008 99
*/

發現了嗎?
只要有 var:= 出現,就是宣告新的變數、挪用新的記憶體空間
所以導致全域變數a的地址被蓋掉了

但當你正這麼想的同時,再來看看下面這個範例

坑B範例
https://play.golang.org/p/3iAo5wIt32D

package main

import "fmt"

var i = 123 // 全域變數

func main() {
	fmt.Println(&i)

	i = 123
	fmt.Println(&i)

	i := 123 // 全新的。func區塊內的區域變數
	fmt.Println(&i)

	i, j := 123, 100
	fmt.Println(&i, j) // 奇怪?i沒有變新的啊
}

/* 運行結果
0x11662a0
0x11662a0
0xc0000b2008
0xc0000b2008 100
*/

只要有 var:= 出現,就會挪用全新的記憶體空間嗎?

答案是:不一定。

程式會去查找目前最小單位的區塊內 是否已經有宣告過的變數,
沒有的話才會宣告新的。

這個變數到底是不是全新的?

看到有 var 會是全新的。
但看到 := 卻是不一定,短變數宣告可以伴隨著未宣告的變數一起出現。

https://play.golang.org/p/E3xcRJjTTjx

package main

import "fmt"

var x = 123 // 全域變數

func main() {
	fmt.Println(&x)

	var x = 123 // 在`func區塊`。全新。
	fmt.Println(&x)

	// var x, y = 123, 100 // 因為x已經宣告過了,不能再用`var`。但以下卻可以
	x, y := 123, 100 // 在`func區塊`。此時x是上面宣告過的區域變數,而y是新的
	fmt.Println(&x, &y)

	if true {
		var x, y = 123, 100 // 在新區域`if區塊`。此時x跟y都是全新的。
		// 可以換成短變數宣告。

		fmt.Println(&x, &y)
	}

	fmt.Println(&x) // 脫離if區域,回到`func區塊`
}

/* 運行結果
0x11662a0
0xc000016080
0xc000016080 0xc000016088
0xc000016090 0xc000016098
0xc000016080
*/

未來會常常看到下面這種用法

connect, err := ...(server)  

或者

result, err := ...

此時:=左邊的兩個變數,都會是區域變數
不是你外面宣告的全域變數。

另外

  • 宣告全域變數只能用var,無法用:=

常數宣告

常數:無法更動、無法刪除的變數
但用法跟變數var一樣,const後面可以接任何型別,

因為常數硬梆梆的,所以單字通常為全大寫

const PI = 3.14159
const HELLO = "Hello World"

【iota】

iota希臘字符,在Golang中是關鍵字之一,用在宣告常數中,
效果為數字遞增iota本身數值從0開始,
便於工程師不用手動打數字0、1、2、3...重複且無聊的事情。

const (
	A = iota       // 0
	B              // 1
	_              // 2 佔位符也會被計算
	C              // 3
	D = iota * 0.1 // 0.4 接續前面的 iota
	E              // 0.5
	F              // 0.6
	G              // 0.7
)

起始值也不一定要從0開始

const (
	X = iota + 100 // 100
	Y              // 101
	Z              // 102
)

也常被拿來作 左移右移(Shift Bit) 運算

const (
	b1 = 1 << iota // 1  右側被塞入0個bit (2^0 二的零次方)
	b2             // 2  右側被塞入1個bit (2^1 二的一次方)
	b3             // 4  右側被塞入2個bit
	b4             // 8  
	b5             // 16 
)

https://play.golang.org/p/jVOzeLxu-mB


上一篇
# Day04 寫程式之前,GO這些很重要
下一篇
# Day06 Go開教基本語法 (fmt)
系列文
Go繁不及備載35

2 則留言

1
hungohung
iT邦新手 5 級 ‧ 2020-12-09 17:08:19

Hi 你好,

這邊這樣寫好像有點讓人誤解寫的到底是ABC的值還是iota那時候是多少?是嘛?

const (
A = iota // 0
B // 1
_ // 2 佔位符也會被計算
C // 3
D = iota * 0.1 // 0.4 接續前面的 iota
E // 5 (應該是iota 5 繼續 x 0,1) 所以應該是0.5才對
F // 6 <== 0.6
G // 7 <== 0.7
)

gjlmotea iT邦新手 5 級 ‧ 2020-12-10 19:56:28 檢舉

感謝糾正^^,已將內文更新

hungohung iT邦新手 5 級 ‧ 2020-12-11 14:24:58 檢舉

沒問題!謝謝你的文章^^

1
eric820209
iT邦新手 5 級 ‧ 2020-12-11 18:29:13

嗨關於坑B的部分

發現了嗎?
這裡一開始的:= 出現,反而沒有挪用新的記憶體空間
可是後來的:= 就又挪用新的記憶體空間

是不是有寫錯或是我哪裡理解錯誤的地方呢

在第一次執行a:=123的時候
記憶體位置的確從
0x53f108 變成 0xc000094018了吧

後面執行a, b := 100, 99的時候
才是都是0xc000094018

是不是有寫反呢

gjlmotea iT邦新手 5 級 ‧ 2020-12-12 16:11:24 檢舉

原先的範例的確寫反了,/images/emoticon/emoticon06.gif
已將之編排做修正,謝謝^^

沒事,繼續拜讀文章XD

我要留言

立即登入留言