packagemainimport("fmt")funcmain(){vari=8// i 佔用了一個記憶體空間varp*int// 宣告 p 是一個 int 的指標,但此時要指向哪還不知道fmt.Printf("Type of p is %T\n",p)fmt.Printf("Type of &i is %T\n",&i)fmt.Println("p =",p)// The zero value of a pointer is nilp=&i// 將 p 指到 i 的記憶體位置fmt.Println("p =",p)// p 所指到的記憶體位置,就是ifmt.Println("&p =",&p)// p 的記憶體位置fmt.Println("*p =",*p)// '*' 代表透過 pointer 顯示該記憶體位置的值*p=20// 透過 pointer 寫入 i 的值fmt.Println("*p =",*p)fmt.Println("i =",i)}/**Type of p is *intType of &i is *intp = <nil>p = 0x10414020&p = 0x1040c128*p = 8*p = 20i = 20**/// 當用 * 宣告為指標時,必須再去指向記憶體位置 &
Passing pointer to a function
123456789101112131415161718192021
packagemainimport("fmt")funcchange(val*int){*val=55}funcmain(){a:=58fmt.Println("value of a before function call is",a)b:=&achange(b)fmt.Println("value of a after function call is",a)}/**value of a before function call is 58value of a after function call is 55**/
packagemainimport("fmt")typeEmployeestruct{firstName,lastNamestringage,salaryint}funcmain(){//creating structure using field namesemp1:=Employee{firstName:"Sam",age:25,salary:500,lastName:"Anderson",}//creating structure without using field namesemp2:=Employee{"Thomas","Paul",29,800}fmt.Println("Employee 1",emp1)fmt.Println(emp1.firstName,emp1.age,emp1.salary,emp1.lastName)fmt.Println("Employee 2",emp2)fmt.Println(emp2.firstName,emp2.age,emp2.salary,emp2.lastName)}/**Employee 1 {Sam Anderson 25 500}Sam 25 500 AndersonEmployee 2 {Thomas Paul 29 800}Thomas 29 800 Paul**/
Anonymous structs
123456789101112131415161718192021
packagemainimport("fmt")funcmain(){emp3:=struct{firstName,lastNamestringage,salaryint}{firstName:"Andreah",lastName:"Nikola",age:31,salary:5000,}fmt.Println("Employee 3",emp3)}// Employee 3 {Andreah Nikola 31 5000}
Anonymous fields
Anonymous fields 因為沒有 name,預設會將 type 當作是自己的 name
1234567891011121314151617181920
packagemainimport("fmt")typePersonstruct{stringint}funcmain(){varpPerson// or p := Person{"Naveen", 50}p.string="leon"p.int=50fmt.Println(p)}// {leon 50}
packagemainimport("fmt")typeVertexstruct{XintYint}funcmain(){v:=Vertex{1,2}p:=&vp.X=1e9// 等同於 (*p).X,但這樣太複雜,因此允許可以只用 p.Xfmt.Println(v)var(v1=Vertex{1,2}// has type Vertexv2=Vertex{X:1}// Y:0 is implicitv3=Vertex{}// X:0 and Y:0p2=&Vertex{1,2}// has type *Vertex)fmt.Println(v1,v2,v3,p2,*p2)}/**{1000000000 2}{1 2} {1 0} {0 0} &{1 2} {1 2}**/
packagemainimport("fmt")typeAddressstruct{city,statestring}typePersonstruct{namestringageintAddress// anonymous struct field 因此 name 就會是 Address}funcmain(){varpPersonp.name="Naveen"p.age=50p.Address=Address{city:"Chicago",state:"Illinois",}fmt.Println("Name:",p.name)fmt.Println("Age:",p.age)fmt.Println("City:",p.city)//city is promoted fieldfmt.Println("State:",p.state)//state is promoted field}
New struct
123456789101112131415161718192021
packagemainimport("fmt")typeVertexstruct{X,Yint}funcmain(){v:=new(Vertex)// 相當於 var v *Vertex = new(Vertex)// 宣告 v 是一個 *Vertex 的指標,並指向 Vertex structfmt.Println(v)v.X,v.Y=11,9fmt.Println(v)}// &{0 0}// &{11 9}
Structs Equality
如果 structs 的 fields 是相等的話,就可以比較,還有裡面的 type 是可以比較的(像是 maps 就無法做比較)
packagemainimport("fmt")typenamestruct{firstNamestringlastNamestring}funcmain(){name1:=name{"Steve","Jobs"}name2:=name{"Steve","Jobs"}ifname1==name2{fmt.Println("name1 and name2 are equal")}else{fmt.Println("name1 and name2 are not equal")}name3:=name{firstName:"Steve",lastName:"Jobs"}name4:=name{}name4.firstName="Steve"ifname3==name4{fmt.Println("name3 and name4 are equal")}else{fmt.Println("name3 and name4 are not equal")}}// name1 and name2 are equal// name3 and name4 are not equal
packagemainimport("fmt")typeauthorstruct{firstNamestringlastNamestringbiostring}func(aauthor)fullName()string{returnfmt.Sprintf("%s %s",a.firstName,a.lastName)}typepoststruct{titlestringcontentstring// Anonymous fields// Go會將嵌入字段預設作為屬性名author}func(ppost)details(){fmt.Println("Title: ",p.title)fmt.Println("Content: ",p.content)fmt.Println("Author: ",p.fullName())fmt.Println("Bio: ",p.bio)}typewebsitestruct{posts[]post}func(wwebsite)contents(){fmt.Println("Contents of Website")for_,v:=rangew.posts{v.details()fmt.Println()}}funcmain(){author1:=author{"Naveen","Ramanathan","Golang Enthusiast",}post1:=post{"Inheritance in Go","Go supports composition instead of inheritance",author1,}post2:=post{"Struct instead of Classes in Go","Go does not support classes but methods can be added to structs",author1,}post3:=post{"Concurrency","Go is a concurrent language and not a parallel one",author1,}w:=website{posts:[]post{post1,post2,post3},}w.contents()}// Contents of Website// Title: Inheritance in Go// Content: Go supports composition instead of inheritance// Author: Naveen Ramanathan// Bio: Golang Enthusiast// Title: Struct instead of Classes in Go// Content: Go does not support classes but methods can be added to structs// Author: Naveen Ramanathan// Bio: Golang Enthusiast// Title: Concurrency// Content: Go is a concurrent language and not a parallel one// Author: Naveen Ramanathan// Bio: Golang Enthusiast
建構子 Constructors
Golang 裡因為沒有類別,也就沒有建構子,但可以自己在外部建立一個建構用函式。
123456789101112131415161718192021222324252627
packagemainimport("fmt")typeTeststruct{astring}func(t*Test)show(){fmt.Println(t.a)}// 用來建構 Test 的假建構子funcnewTest()(test*Test){test=&Test{a:"foobar"}// 這裡會回傳一個型態是 *Test 建構體的 test 變數return}funcmain(){b:=newTest()b.show()// 輸出:foobar}// foobar
Example 2
12345678910111213141516171819202122
// employee/employee.gopackageemployeeimport("fmt")typeemployeestruct{// 改成小寫,不需要外面呼叫,必須都要透過 New 來產生firstNamestringlastNamestringtotalLeavesintleavesTakenint}funcNew(firstNamestring,lastNamestring,totalLeaveint,leavesTakenint)employee{e:=employee{firstName,lastName,totalLeave,leavesTaken}returne}func(eemployee)LeavesRemaining(){fmt.Printf("%s %s has %d leaves remaining",e.firstName,e.lastName,(e.totalLeaves-e.leavesTaken))}
packagemainimport("fmt""math")typeMyFloatfloat64// create a type alias for the built-in type float64sfunc(fMyFloat)Abs()float64{iff<0{returnfloat64(-f)}returnfloat64(f)}funcmain(){f:=MyFloat(-math.Sqrt2)fmt.Println(f.Abs())}// 1.4142135623730951
packagemainimport("fmt")// // 先定義一個 Foobar 建構體,然後有個叫做 a 的字串成員typeFoobarstruct{astring}// 定義一個屬於 Foobar 的 test 方法func(f*Foobar)test(){// 接收來自 Foobar 的 afmt.Println(f.a)}funcmain(){a:=&Foobar{a:"a: hello, world 1"}// a point to Foobar memory addressvarb=Foobar{a:"b: hello, world 2"}varc=&Foobar{a:"c: hello, world 3"}// c point to Foobar memory address 後面沒加 type 會自動判斷vard*Foobar=&Foobar{a:"d: hello, world 4"}// d point to Foobar memory addressfmt.Printf("%T, %T, %T, %T\n",a,b,c,d)a.test()// (*a).test()b.test()// (&b).test() or (*(&b)).test() 因為是 point 的 method 所以要給 addressc.test()// (*c).test()d.test()// (*d).test()}/***main.Foobar, main.Foobar, *main.Foobar, *main.Foobara: hello, world 1b: hello, world 2c: hello, world 3d: hello, world 4**/
packagemainimport("fmt")typerectanglestruct{lengthintwidthint}funcarea(rrectangle){fmt.Printf("Area Function result: %d\n",(r.length*r.width))}func(rrectangle)area(){fmt.Printf("Area Method result: %d\n",(r.length*r.width))}funcmain(){r:=rectangle{length:10,width:5,}area(r)r.area()p:=&r/* compilation error, cannot use p (type *rectangle) as type rectangle in argument to area *///area(p)p.area()//calling value receiver with a pointer}// Area Function result: 50// Area Method result: 50// Area Method result: 50
packagemainimport("fmt")typerectanglestruct{lengthintwidthint}funcperimeter(r*rectangle){fmt.Println("perimeter function output:",2*(r.length+r.width))}func(r*rectangle)perimeter(){fmt.Println("perimeter method output:",2*(r.length+r.width))}funcmain(){r:=rectangle{length:10,width:5,}p:=&r//pointer to rperimeter(p)p.perimeter()/* cannot use r (type rectangle) as type *rectangle in argument to perimeter *///perimeter(r)r.perimeter()//calling pointer receiver with a value}// perimeter function output: 30// perimeter method output: 30// perimeter method output: 30
Methods on non struct types
method 必須定義成 local type 才可以,因此像要再 int 新增 method 則會出現 error cannot define new methods on non-local type int,必須定義新的 type 才行
12345678910111213141516171819
packagemainimport"fmt"typemyIntint// 不可以直接用 intfunc(amyInt)add(bmyInt)myInt{returna+b}funcmain(){num1:=myInt(5)num2:=myInt(10)sum:=num1.add(num2)fmt.Println("Sum is",sum)}// Sum is 15
function use pointer or value ??
先說結論: 如果只是要讀值,可以使用 Value 或 Pointer 方式,但是要寫入,則只能用 Pointer 方式。