天天看點

Go_結構體、方法、接口

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)