go 的變數是 name type
, 老是寫成 c 的 type name
go 的 type name struct
c 的typedef struct name
對比 PHP:
PHP 中沒有 struct
型別,這裡對比 C 的 struct
- 支援匿名欄位「嵌入欄位」
- type = c 的 typedef
- 初始化有所區別
- 宣告
- 初始化
- 訪問
先看一下 C 中的 struct
// 結構體宣告常用的兩種
// 通過 typedef
typedef struct Human {
char* name;
int age;
} *pHuman;
// 直接宣告
struct Human {
char* name;
int age;
};
struct Staff {
Human* human; // 指向結構體的指標
Human human; // 包含結構體
pHuman human; // 包含指向結構體的指標
int wage;
}
再看 Go
type Human struct {
name string
age int
}
var tom Human
// 通過賦值初始化
tom.name, tom.age = "Tom", 18
// 詳細初始化
jerry := Human{age:25, name:"Jerry"}
// 按照結構體宣告順序
peter := Human{"Peter", 34}
// 通過 . 訪問
fmt.Printf("%s is %d old\n", tom.name, tom.age)
匿名欄位
匿名欄位也叫「嵌入欄位」顧名思義,嵌入到一個結構體的欄位
只提供型別,而不寫欄位名。『通過這個來定義』
- 支援:型別、自定型別、結構體
- 如果是結構體:隱式的引入這個結構體的欄位到新結構體
- 重複欄位最外層優先原則,裡層通過 隱式型別訪問
type Staff struct {
Human // 隱式的引入 Human 的欄位
wage int
age float32 // 覆蓋 Human 的 age
}
tom := Staff{Human{"Tom", 18}, 1000, 18.5}
jerr := Staff{Human:Human{age:32, name:"Jerr"}, wage: 2000, age: 32.5}
fmt.Printf("%s is %f old,%d years, wage is %d", tom.name, tom.Human.age, tom.age, tom.wage)
fmt.Printf("%s is %f old,%d years, wage is %d", jerr.name, jerr.Human.age, jerr.age, jerr.wage)
看完了 go 的面相物件後,emmmm... 感覺有點顛覆。首先是告別 class
。 然後一系列的 static public protected private
都沒有了,甚至是 extends parent
都省了。我現在還很不習慣... 魔術方法?建構函式?...且邊學邊看
methd
"A method is a function with an implicit first argument, called a receiver."
這麼理解呢,這麼說
一個 method
就是 function 的第一個『引數』是一個 receiver
「接收者,接收這個函式的是誰即是方法的所有者」\
如果還沒明白的話就再通俗一點
receiver = class
method = 成員函式
// 下面這個 function 是 ReceiverType (class) 的一個 method,
// funcName 首字母大寫是公有、小寫是私有
// ReceiverType 可以是結構體、自定義型別、內建型別「PS這個是真的騷」
func (r ReceiverType) funcName(parameters) {}
指標 作為 receiver
go 知道我們需要呼叫或傳遞的是指標,你寫值他會自動幫你去用指標。理解這個先來理解下面 c 程式碼
void setZore(int* a) {
*a = 0;
// 在 go 中可以理解為
a = 0; // go 自動給你變成 *a = 0
}
int x = 10;
// 在 C 中必須傳遞地址 go 中可以是 setZore(x)
setZore(&x);
如果一個 method 的 receiver 是 *T, 你可以在一個 T 型別的例項變數 V 上面呼叫這個 method,而不需要 &V 去呼叫這個 method
如果一個 method 的 receiver 是 T,你可以在一個 T 型別的變數 P 上面呼叫這個 method,而不需要 P 去呼叫這個 method
繼承跟過載
繼承跟過載都跟匿名欄位一樣的
- 繼承:如果匿名欄位實現一個 method 包含這個匿名欄位的結構體也能使用這個 method
- 重寫:在包含者上面重新定義這個 method,重寫匿名欄位的方法
type Human struct {
name string
age int
}
type Employee struct {
Human
wage int
}
func (h *Human) Say() {
fmt.Printf("Hi, I am %s, My age is %d", h.name, h.age)
}
// Employee 重寫 Say
func (e *Employee) Say() {
fmt.Printf("Hi, I am %s, %d old year, wage is %d per mothn", e.name, e.age, e.wage)
}