Skip to content

Instantly share code, notes, and snippets.

@changtimwu
Last active August 29, 2015 14:00
Show Gist options
  • Save changtimwu/11270600 to your computer and use it in GitHub Desktop.
Save changtimwu/11270600 to your computer and use it in GitHub Desktop.
go study notes

var:= 的差異

  • := 一定要給初值
b:=3
baz:= []int {3,4,5}
baz:= [3]int   // error! 缺乏初值
  • var 可以給初值也可以不給
var a = int(3) // 給初值
var b          // 不給初值
println("b initial val=", b)   //會有預設初值 0
b = 3          // 事後 assign
a := 3         // error! :=是宣告, 已經宣告過了, 不可以重複宣告

var az []int=[]int {3,4,5}  //給初值
var bz []int                 //沒給初值
bz = []int{5, 6, 7, 9, 3}    // 事後給
bz = []int{3, 7, 9, 11, 5}   // 可以重複給, 原本內容會被gc?
  • 在function 外只能用 var
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"])
}

array 的 assign

var ary [5]int
ary[1]=33 // ok
ary[6]=77 // error! out of range
ary=[5]int {7,8,9,10,11} // ok!
ary=[3]int {3,4,5}  //error! 不同長度的array會被視為不同type,  [3]int 不能直接assign給 [5]int

var ary1 []int
ary1=[]int {3,4,5}  //ok

ary1=[]int {4,5,6,7} // ok
ary1=[2]int {1,2} // error! 會被視為不同type, [2]int 與 []int 不能直接assign, 
ary1=[]int {1,2} // ok

GO的array 與C array的差異

  • http://golang.org/doc/effective_go.html#arrays
    • Arrays are values. Assigning one array to another copies all the elements.
    • In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it.
    • The size of an array is part of its type. The types [10]int and [20]int are distinct. 長度不同type就不同
  • 資料很大記得改用pointer to array or slice
func passptr(aryptr *[4]int) {
    aryptr[1] = 999 // reference through pointer is the same way as accessing variable
}

func passslice(arysl []int) {
    arysl[1] += 1 // reference through pointer is the same way as accessing variable
}

func array_pass() {
    ary1 := [4]int{4, 5, 6, 7}
    passptr(&ary1)
    fmt.Println("ary1 becomes ", ary1)
    passslice(ary1[:])
    fmt.Println("ary1 becomes ", ary1)
}
  • most array programming in Go is done with slices rather than simple arrays.
  • _If the data exceeds the capacity, the slice is reallocated. _
func fixed_length_array_not_appendable() {                                                                
    a := [2]string{"John", "Paul"}
    fmt.Println("len(a)=", len(a), "cap(a)=", cap(a))
    //a = append(a, "mary") // array size 固定, 不可以append 
}
func append_to_slice_pointing_array() {
    a := [2]string{"John", "Paul"}
    asl := a[:]

    fmt.Println("len(asl)=", len(asl), "cap(asl)=", cap(asl))
    asl = append(asl, "mary") // trigger an reallocation
    // slice 可以自由 append 萬一實際容量不夠, 它會自動realloc 
    fmt.Println("len(asl)=", len(asl), "cap(asl)=", cap(asl))
    fmt.Println("asl=", asl)
}

new 跟make的差異

  • new 都是單一值
v1:= new(Vertex)
  • make可以拿來生成slice or map
u:=make(map[string]int) 
bazb:=make([]int,5)
  • 都不能設初值
v1:= new(Vertex){3,4} //error
bazb:=make([]int,5){1,2,3,4,5} //error
  • 下列四個是否一樣?
var ary1 [5]int
ary2:=[5]int{}
var ary3 = make([]int, 5)
ary4:=make([]int,5)

result

ary1 type=[5]int, len=5, content=[0 0 0 0 0]
ary2 type=[5]int, len=5, content=[0 0 0 0 0]
ary3 type=[]int, len=5, content=[0 0 0 0 0]
ary4 type=[]int, len=5, content=[0 0 0 0 0]
  • make 與直接宣告的差異
var ary1 [5]int
fmt.Printf("ary1 type=%T, len=%d, content=%v\n", ary1, len(ary1), ary1)
var ary2 = make([]int, 5)
fmt.Printf("ary2 type=%T, len=%d, content=%v\n", ary2, len(ary2), ary2)                         
// output 
//ary1 type=[5]int, len=5, content=[0 0 0 0 0]
//ary2 type=[]int, len=5, content=[0 0 0 0 0]
  • [] 其實叫做 slice, 彈性比fixed length array 高
    var ary1 []int = []int{1, 2}
    fmt.Printf("ary1 type=%T, len=%d, content=%v\n", ary1, len(ary1), ary1)
    // result: ary1 type=[]int, len=2, content=[1 2]
    
    ary1 = append(ary1, 44)
    fmt.Printf("ary1 type=%T, len=%d, content=%v\n", ary1, len(ary1), ary1)
    // result: ary1 type=[]int, len=3, content=[1 2 44]

    var ary2 [2]int
    fmt.Printf("ary2 type=%T, len=%d, content=%v\n", ary2, len(ary2), ary2)
    // result: ary2 type=[2]int, len=2, content=[0 0]
    
    ary2 = append(ary2, 44) // error! first argument to append must be slice; have [2]int
     

Slice

  • 參考 http://blog.golang.org/slices
  • 重點節錄 it is not a pointer to the first array element (as would be the case in C). This means that when you assign or pass around an array value you will make a copy of its contents. (To avoid the copy you could pass a pointer to the array, but then that's a pointer to an array, not an array.
  • so
  ary1 := [4]int{4, 5, 6, 7}
  ary2 := ary1
  ary1[2] = 999                                                                                   
  fmt.Println("ary1=", ary1, "ary2=", ary2)
  //result
  ary1= [4 5 999 7] ary2= [4 5 6 7]
  • [...] 代表自動算count element , 跟[] (slice) 意義不一樣
    ary1 := [...]int{4, 5, 6, 7}
    ary2 := ary1
    ary1[2] = 999
    fmt.Println("ary1=", ary1, "ary2=", ary2)                                                       
    fmt.Printf("ary1's type = %T , ary2's type = %T\n", ary1, ary2)
    //result:
    //ary1= [4 5 999 7] ary2= [4 5 6 7]
    //ary1's type = [4]int , ary2's type = [4]int
  • pointer to array 長這樣
    ary1 := [4]int{4, 5, 6, 7}
    aryptr1 := new([4]int)
    aryptr1 = &ary1
    fmt.Printf("aryptr1's type = %T\n", aryptr1)
    aryptr1[1] = 999 // reference through pointer is the same way as accessing variable
    fmt.Println("ary1 becomes ", ary1)
    aryptr1[5] = 99 // error!  Unlike C, in Go pointers have range protection
  • interface 當func parameter 的type, caller可以傳pointer 或var本身, it dependents the variable's type implementation
type Person interface {
    getage() int
}

type Farmer struct {
    age int
}

func (f *Farmer) getage() int {
    return f.age
}

func showage(p Person) {                                                                        
    println("the age is ", p.getage())
}

type Carpenter struct {
    age int
}

func (cp Carpenter) getage() int {
    return cp.age
}


func main() {
    f := Farmer{age: 10}
    showage(&f)
    //showage(f) // error Farmer doesn't implement Person

    cp := Carpenter{age: 12}
    showage(cp)
    //showage(&cp) // error! *Carpenter doesn't implement Person
}
  • 這個例子中我們可以說
    • *Farmer implement了 Person interface, 但 Farmer 並沒有
    • Carpenter implement了 Person interface, 但 *Carpenter 並沒有
  • 為你的type定義String function, 可以讓你的type用fmt.Println印出來
type CBack struct {
    id int
    d  string
}

func (cb CBack) String() string {
    return fmt.Sprintf("id=%d, d=%s", cb.id, cb.d)
}

func main () {
    cb := CBack{id: 3, d: "hello"}
    fmt.Println("cb is ", cb)
}

Type Casting

@changtimwu
Copy link
Author

map 一定要用make 才會指到實際map變數, 不然只是一個空的 nil map ( 意思是沒有指到任何空間的 reference map)
Map types are reference types, like pointers or slices, and so the value of m above is nil; it doesn't point to an initialized map. A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function:

var Pool = make(map[int]string)
var Pool = map[int]string {} // error!
func test_map() {
    var Pool2 map[int]string = Pool //ok Pool2 has the same reference as Pool
    Pool[3] = "this is 3"
    Pool2[10] = nil
    fmt.Println("Pool=", Pool)
    fmt.Println("Pool2=", Pool2)
    delete(Pool2, 10)                                                                               
    fmt.Println("Pool=", Pool)
    fmt.Println("Pool2=", Pool2)
}
func t2() {
  var m map[string]int
  q:=make(map[string]int)
  n:=map[string]int { "marry":1}


  n["jj"]=4 // ok
  m["jj"]=3  // error! you can't add new key  to nil map
  q["jj"]=3 //ok, make would allocate an actual map with zero elements
}
func t2() {
  var m map[string]int
  n:=map[string]int { "marry":1}
  m=n  // m is referenced to n
  m["jj"]=4   // ok! m & n are pointing to the sam map
}

@changtimwu
Copy link
Author

@changtimwu
Copy link
Author

reflect ( http://golang.org/pkg/reflect/ )裡的 Value type比較像 C的 pointer, 可以hold各種type value value, 可以任意casting, 錯了就panic.

@changtimwu
Copy link
Author

http://godoc.org/github.com/vmihailenco/msgpack 會遇到 decode 出來的object 無法餵給 json encode, 最大的問題在於它encode出來的map key type 是 interface{}, 沒有先define struct的話, json是看不懂的,
解法是把自訂 dec.DecodeMapFunc, 把map key 先都用string處理.

@changtimwu
Copy link
Author

github.com/vmihailenco/msgpack 有提供標準 codec 界面

enc:=msgpack.NewEncoder(conn)
enc.encode(v)
dec:=msgpack.NewDecoder(conn)
dec.decode(&v)

這無法把它當 smith 用, 因為 smith 每個 object 前面都還要加 4byte length.

Another problem is that its decoder requires the input reader more capable of io.Reader. It's bufReader which is defined in https://github.com/vmihailenco/bufio. If the input reader is a general io.Reader, not bufReader, it will prompt the input reader like the following code.

  brd, ok := rd.(bufReader)
  if !ok {
        brd = bufio.NewReader(rd)
  }

However, when I pass a TCP connection to it, all subsequent decodes are returned with error invalid value.

@changtimwu
Copy link
Author

func myfunc(args ...interface{}) {
    for i, arg := range args {
      fmt.Printf("%vth %v \n",i, arg)
    }
}
myfunc(  1,"asdf", 4,5)

@changtimwu
Copy link
Author

map 不必特別用 pointer, 這種collection type, assignment其實都是 change reference

var callback_seq map[string]int = map[string]int{"$": 0}

func getseqp() *map[string]int {
    callback_seq["$"]++
    return &callback_seq
}

func getseq() map[string]int {
    callback_seq["$"]++
    return callback_seq
}
func main() {
    for i := 0; i < 10; i++ {
        seq := getseq()
        fmt.Println(seq)
        seq["$"]--
    }
}    

@changtimwu
Copy link
Author

There is no pointer to interface.

type human interface {
    getAge() int
}
// you would get error 
func f1(h *human) {
    fmt.Println("h.age=", h.getAge())
}

plain interface argument can accept both struct and pointer to struct

type human interface {
    getAge() int
}
func f1(h human) {
    fmt.Println("h.age=", h.getAge())
}
type student struct {
    age int
}
func (student) getAge() int {
    return 17
}
func main() {
    h := student{33}
    f1(h)  // ok!
    f1(&h)  // ok!
}  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment