1. 結構體
1.1 定義結構體
Go語言中沒有類的概念,也不支援繼承。go中可用結構體來封轉多資料類型資料,據說Go語言中結構體的組合方式更具有擴充性和靈活性
type identifier struct{
field1 type1
field2 type2
...
}
type Person struct{
Name string
Age int
}
//結構體中字段的類型可以是任何類型,包括函數類型,接口類型,甚至結構體類型本身
type ListNode struct{
Val int
Next *ListNode
string //也可以不指定字段名,這種為匿名字段,一個結構體隻能有一個匿名字段
}
1.2 操作結構體
s1 := new(Person)
s1.Name= "哈哈"
s1.string="我是匿名字段指派"
//必須全字段指派
s2 := Person{"zhangsan",32,"remark"}
//部分字段指派
s3 := &Person{
Name:"lisi",
Age:33
}
1.3 标簽
go語言中結構體除了字段的名稱和類型外還有一個可選的标簽tag,标記的tag隻有reflect包可以通路到,一般用于orm或者json的資料傳遞,下面這段代碼示範了如何為結構體打标簽。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
//可以使用go自帶的json包将聲明的結構體變量轉變為json字元串。
func ToJson(p *Person)(string,error){
bytes, err := json.Marshal(p)
if err != nil {
retrun "",nil
}
return string(bytes),nil
}
//如果我們沒有給結構體打标簽輸出的json字元串如下所示
{"Name":"james","Age":35}
//如果我們給結構體打過标簽之後輸出的json字元串如下所示
{"name":"james","age":35}
1.4 内嵌結構體
結構體作為一種資料類型也可以将其聲明為匿名字段,此時我們稱其為内嵌結構體。
type A struct {
X,Y int
}
type B struct {
A
Name String
}
//使用
b := new(B)
b.X = 10
b.Y = 20
b.Name = "test"
//嵌套規則
type A struct{
X,Y int
}
type B struct{
a A
Name string
X int
}
type C struct{
aa A
b B
X int
}
c := new(C)
c.aa.X = 10
c.b.X = 10
2.方法
2.1定義方法
方法與函數類似,隻不過在定義方法時會在func 和 方法名之間添加一個參數 (r Receiver)
func (r Receiver)func_name(){
//body
}
//例子
type Person struct {
name string
}
func (p Person) GetName() string {
return p.name
}
func main() {
p := Person{
name:"james",
}
fmt.Println(p.GetName())
}
2.2 方法接收者
對于一個方法來說接收者分為兩種類型:值接收者和指針接收者。上面的GetName的接收者就是值接收者
func (p *Person)SetName(name string){
p.name = name
}
使用值接收者,在調用的時候使用的其實是值接受者的一個拷貝,是以對該值的任何操作,都不會影響原來的類型變量。
但是如果使用指針接收者的話,在方法體内的修改就會影響原來的變量,在go語言中還有一點比較特殊,我們使用值接收者定義的方法使用指針來調用也是可以的,反過來也是如此
func main(){
p := &Person{
name: "james",
}
fmt.Println(p.GetName())
p1 := Person{
name: "james",
}
p1.SetName("kobe")
fmt.Println(p1.GetName())
}
3. 接口
3.1 定義接口
接口相當于一種規範,它需要做的是誰想要實作我這個接口要做哪些内容,而不是怎麼做
type Namer interface {
Method1(param_list) return_type
Method2(param_list) return_type
...
}
//實作接口
type Animal interface {
Eat()
}
type Bird struct {
Name string
}
func (b Bird) Eat() {
fmt.Println(b.Name + "吃蟲")
}
type Dog struct {
Name string
}
func (d Dog) Eat() {
fmt.Println(d.Name + "吃肉")
}
func EatWhat(a Animal) {
a.Eat()
}
func main() {
b := Bird{"Bird"}
d := Dog{"Dog"}
EatWhat(b)
EatWhat(d)
}
3.2 斷言
有些時候方法傳遞進來的參數可能是一個接口類型,但是我們要繼續判斷是哪個具體的類型才能進行下一步操作,這時就用到了類型斷言,下面我們通過一個例子來進行講解:
func IsDog(a Animal) bool {
if v, ok := a.(Dog); ok {
fmt.Println(v)
return true
}
return false
}
func WhatType(a Animal) {
switch a.(type) {
case Dog:
fmt.Println("Dog")
case Bird:
fmt.Println("Bird")
default:
fmt.Println("error")
}
}
3.3 空接口
空接口是一個比較特殊的類型,因為其内部沒有定義任何方法是以空接口可以表示任何一個類型,
var any interface{}
any = 1
fmt.Println(any)
any = "hello"
fmt.Println(any)
any = false
fmt.Println(any)