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
  1. 宣告變數,不給初始值

     var s string
     fmt.Println(s) // ""
    
  2. 一次宣告多個變數,並給初始值(可省略型別)

     var i, j, k int                 // int, int, int
     var b, f, s = true, 2.3, "four" // bool, float64, string
    
  3. 接收 return 值

     var f, err = os.Open(name) // os.Open returns a file and an error
    

簡寫

宣告時,省略 var

name := expression
  1. 省略型別宣告

     i, j := 0, 1
    
  2. 接收 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
注意事項

使用 := 時,左邊的變數名稱,至少要有一個是新的。

  1. 至少要有一個是新的變數名稱

     in, err := os.Open(infile)
     // ...
     out, err := os.Create(outfile)
    

    以上,雖然 err 重覆,但 out 是新的變數名稱,compile 會過。

  2. 都是舊的

     f, err := os.Open(infile)
     // ...
     f, err := os.Create(outfile) // compile error: no new variables
    

    以上,ferr 都是舊的變數,所以在第二次,還是使用 := 時,compile 會錯。通常 compile 會報錯,都不是什麼大問題,修正就好了。

指標 (Pointer)

使用方法及觀念與 C 相同,& 取變數的指標,* 取指標內的值;需注意的是,C 可以對指標做位移,但 Go 不行。unsafe

unsafe. Golang 有 unsafe 套件,專門用在與 C 串接。需轉成 unsafe 的 pointer 才能做指標位移。
  1. 用法

     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"
    
  2. 不可做指標位移:

     a := 10
     b := &a
     b++     // invalid operation: b++ (non-numeric type *int)
    

Tuple

數組

  1. Tuple Assignment (1)

     x, y = y, x
     a[i], a[j] = a[j], a[i]
    
  2. Tuple Assignment (2): GCD sample

     func gcd(x, y int) int {
    
         for y != 0 {
             x, y = y, x%y
         }
    
         return x
     }
    
  3. Return Tuple

     func swap(x, y int) (int, int) {
         return y, x
     }
    

Type Declaration

Go 可以使用 type,利用原有的資料型別,宣告一個新的資料型別,最常用在 struct 宣告,使用 type 重新宣告資料型別,可以增加程式碼的可讀性。

eg:

  1. 華氏、攝氏型別宣告與轉換

     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) }
    
  2. Strong Type Detection 雖然 CelsiusFahrenheit 都是 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
    
  3. 型別轉換(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"!
    

    注意,雖然 CelsiusFahrenheit 底層都是 float64,但都還是要視為不同的型別。

Package and Imports

Go Package 概念跟 Java package, C/PHP namespace 類似。主要用意:

  1. Modularity
  2. Encapsulation
  3. 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 關鍵字,而是利用字母的大、小寫來區分 privatepublic。如果變數或 function 是小寫開頭,則為 private,反之,大寫就是 public

注意 private 變數,在同 package 下,存取不同 struct private 變數。

變數 Scope

與其他語言相同,與 java 不同點是有 global 變數。

變數找尋的順序:local block -> function block -> global

results matching ""

    No results matching ""