02 程式結構與語法
關鍵字
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
內建常數
true false iota nil
資料型別
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex64 complex128
bool byte rune string error
內建 Function
make len cap new append copy
delete
close
complex real imag
panic recover
宣告 Declaraion
完整寫法
var name type = expression
宣告變數,不給初始值
var s string fmt.Println(s) // ""
一次宣告多個變數,並給初始值(可省略型別)
var i, j, k int // int, int, int var b, f, s = true, 2.3, "four" // bool, float64, string
接收 return 值
var f, err = os.Open(name) // os.Open returns a file and an error
簡寫
宣告時,省略 var
。
name := expression
省略型別宣告
i, j := 0, 1
接收 return 值
anim := gif.GIF{LoopCount: nframes} freq := rand.Float64() * 3.0 t := 0.0 f, err := os.Open(name) if err != nil { return err } // ...use f... f.Close()
Default Type
當省略型別時,
- 整數型別預設是 int
- 浮點數預設是 float64
i := 0 // int
f := 0.0 // float64
s := "" // string
注意事項
使用 :=
時,左邊的變數名稱,至少要有一個是新的。
至少要有一個是新的變數名稱
in, err := os.Open(infile) // ... out, err := os.Create(outfile)
以上,雖然
err
重覆,但out
是新的變數名稱,compile 會過。都是舊的
f, err := os.Open(infile) // ... f, err := os.Create(outfile) // compile error: no new variables
以上,
f
與err
都是舊的變數,所以在第二次,還是使用:=
時,compile 會錯。通常 compile 會報錯,都不是什麼大問題,修正就好了。
指標 (Pointer)
使用方法及觀念與 C 相同,&
取變數的指標,*
取指標內的值;需注意的是,C 可以對指標做位移,但 Go 不行。unsafe
unsafe. Golang 有 unsafe
套件,專門用在與 C 串接。需轉成 unsafe 的 pointer 才能做指標位移。 ↩
用法
x := 1 p := &x // p, of type *int, points to x fmt.Println(*p) // "1" *p = 2 // equivalent to x = 2 fmt.Println(x) // "2"
不可做指標位移:
a := 10 b := &a b++ // invalid operation: b++ (non-numeric type *int)
Tuple
數組
Tuple Assignment (1)
x, y = y, x a[i], a[j] = a[j], a[i]
Tuple Assignment (2): GCD sample
func gcd(x, y int) int { for y != 0 { x, y = y, x%y } return x }
Return Tuple
func swap(x, y int) (int, int) { return y, x }
Type Declaration
Go 可以使用 type
,利用原有的資料型別,宣告一個新的資料型別,最常用在 struct
宣告,使用 type
重新宣告資料型別,可以增加程式碼的可讀性。
eg:
華氏、攝氏型別宣告與轉換
package tempconv import "fmt" type Celsius float64 type Fahrenheit float64 const ( AbsoluteZeroC Celsius = -273.15 FreezingC Celsius = 0 BoilingC Celsius = 100 ) func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
Strong Type Detection 雖然
Celsius
與Fahrenheit
都是float64
,但還是遵守 Strong Type 原則,兩者不能直接做運算。如下:fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C boilingF := CToF(BoilingC) fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F fmt.Printf("%g\n", boilingF-FreezingC) // compile error: type mismatch
型別轉換(cast)
var c Celsius var f Fahrenheit fmt.Println(c == 0) // "true" fmt.Println(f >= 0) // "true" fmt.Println(c == f) // compile error: type mismatch fmt.Println(c == Celsius(f)) // "true"!
注意,雖然
Celsius
及Fahrenheit
底層都是float64
,但都還是要視為不同的型別。
Package and Imports
Go Package 概念跟 Java package, C/PHP namespace 類似。主要用意:
- Modularity
- Encapsulation
- Reuse
package 命名時要注意,除了 main
之外,目錄的名稱要與 package 相同。
import 的路徑,由 $GOPATH/src
以下目錄開始。
比如有一個專案路徑 gopl.io/ch1/
,package 命名 helloworld
, 則開一個 helloworld
目錄。完整路徑 $GOPATH/src/gopl.io/ch1/helloworld
import 則用
import "gopl.io/ch1/helloworld"
Package Initialization
package 中,可以在某一個程式檔案,定義 func init()
。當 package 被載入時,會先執行 init
的程式碼。
目錄結構:
.
├── main.go
└── test
└── utils.go
程式碼:
utils.go
package test import "fmt" func init() { fmt.Println("test package init") } // Println ... func Println(s string) { fmt.Println(s) }
main.go
package main import ( "fmt" "go_test/class02/test" ) func main() { fmt.Println("start...") test.Println("hello world!!!") }
結果
test package init start... hello world!!!
變數 Visible
Go 沒有 private
and public
關鍵字,而是利用字母的大、小寫來區分 private
及 public
。如果變數或 function 是小寫開頭,則為 private,反之,大寫就是 public。
注意 private 變數,在同 package 下,存取不同 struct private 變數。
變數 Scope
與其他語言相同,與 java 不同點是有 global 變數。
變數找尋的順序:local block -> function block -> global