📢 本文由 gemini-3-flash-preview 翻譯
Golang 系列
Hello GoLang:
https://blog.yexca.net/archives/154
GoLang (var and const) 變數與常數:
https://blog.yexca.net/archives/155
GoLang (func) 函式:
https://blog.yexca.net/archives/156
GoLang (slice and map) 切片:
https://blog.yexca.net/archives/160
GoLang (OOP) 物件導向: 本文
GoLang (reflect) 反射:
https://blog.yexca.net/archives/204
GoLang (struct tag) 結構體標籤:
https://blog.yexca.net/archives/205
GoLang (goroutine) Go 協程:
https://blog.yexca.net/archives/206
GoLang (channel) 通道:
https://blog.yexca.net/archives/207
透過使用結構體構建類別與物件的概念
了解物件導向:
物件導向基礎
struct
首先是自訂型別,使用 type 關鍵字,類似於 C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| package main
import "fmt"
type myType int
func main() {
var a myType
fmt.Println("a =", a)
fmt.Printf("type of a is %T", a)
}
/*
* 輸出
* a = 0
* type of a is main.myTye
*/
|
定義型別使用 struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| package main
import "fmt"
type Person struct {
name string
age int
}
fun main() {
var zhang Person
zhang.name = "zhangSan"
zhang.age = 20
fmt.Print(zhang)
}
|
函式傳遞相關,不使用指標是傳值 (Value Passing)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| package main
import "fmt"
type Person struct {
name string
age int
}
// 傳值,不會修改原始資料
func changeName(person Person) {
person.name = "liSi"
}
// 傳址,會修改原始資料
func changeAge(person *Person) {
person.age = 18
}
func main() {
var zhang Person
zhang.name = "zhangSan"
zhang.age = 20
fmt.Println(zhang)
changeName(zhang)
fmt.Println(zhang)
changeAge(&zhang)
fmt.Println(zhang)
}
|
封裝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| package main
import "fmt"
// 類別
type Person struct {
// 屬性
name string
age int
}
// 類別的方法
func (this *Person) SetName(name string) {
this.name = name
}
func (this *Person) SetAge(age int) {
this.age = age
}
func (this *Person) GetName() string {
return this.name
}
func (this *Person) GetAge() int {
return this.age
}
func main() {
person := Person{name: "zhangSan", age: 18}
fmt.Println(person)
}
|
注意到上述類別名稱、方法名稱首字母為大寫,代表該類別、方法可以被其他套件存取 (java public),若首字母小寫則只能由此套件存取 (java private),屬性名稱也是同理
繼承
以下程式碼處於同一檔案,父類別
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 父類別
type Person struct {
name string
age int
}
// 父類別的方法
func (this *Person) Eat() {
fmt.Println("Person Eat...")
}
func (this *Person) Walk() {
fmt.Println("Person Walk...")
}
|
子類別
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 子類別
type SuperMan struct {
Person // 繼承父類別
level int // 子類別屬性
}
// 子類別覆寫父類別方法
func (this *SuperMan) Walk() {
fmt.Println("SuperMan Walk")
}
// 子類別特有方法
func (this *SuperMan) Fly() {}
|
main 函式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| func main() {
// 定義子類別屬性,方式一
superMan1 := SuperMan{Person{"zhangSan", 18}, 4}
// 定義子類別屬性,方式二
var superMan2 SuperMan
superMan2.name = "liSi" // 因為同一個套件,可以存取父類別屬性
superMan2.age = 20
superMan2.level = 5
// 子類別呼叫父類別方法
superMan1.Eat()
// 子類別覆寫方法
superMan1.Walk()
// 子類別方法
superMan2.Fly()
}
|
多型
以下程式碼處於同一檔案,定義介面
1
2
3
4
5
6
| // 介面,本質是一個指標
type Animal interface {
Sleep()
GetName() string
GetType() string
}
|
實作類別一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // 實作類別一
type Cat struct {
name string
kind string
}
// 實作介面所有方法
func (this *Cat) Sleep() {
fmt.Println("Cat Sleep()")
}
func (this *Cat) GetName() string {
return this.name
}
func (this *Cat) GetType() string {
return this.kind
}
|
實作類別二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // 實作類別二
type Dog struct {
name string
kind string
}
// 實作介面所有方法
func (this *Dog) Sleep() {
fmt.Println("Cat Sleep()")
}
func (this *Dog) GetName() string {
return this.name
}
func (this *Dog) GetType() string {
return this.kind
}
func ShowAnimal(animal Animal) {
fmt.Println(animal)
}
|
main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| func ShowAnimal(animal Animal) {
fmt.Println(animal)
}
func main() {
var animal Animal
animal = &Cat{"cat1", "cat"}
animal.Sleep()
animal = &Dog{"dog1", "dog"}
animal.Sleep()
cat := Cat{"cat2", "cat"}
dog := Dog{"dog2", "dog"}
ShowAnimal(&cat)
ShowAnimal(&dog)
}
|
萬用型別與斷言
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| package main
import "fmt"
// 使用空介面表示萬用資料型別
func f(arg interface{}) {
// 型別斷言機制(即型別轉換)
value, flag := arg.(string)
if !flag {
fmt.Println("arg is not string type")
} else {
fmt.Println("arg is string type, arg =", value)
}
}
func main() {
// 可以傳入任意資料型別,包括自訂
f("abc")
f(123)
f(3.14)
}
/*
* 輸出
* arg is string type, arg = abc
* arg is not string type
* arg is not string type
*/
|