go语法-结构体和接口-细节

 

结构体和接口对于前端背景的我来说,还是有一些新的知识点,这主要提现在细节上。比如方法和函数不一样。

方法只有struct的实例才能调用。而函数就是大家认识的函数,没有任何限制。

9,接口断言

type Shape interface {

  peri()

  area()

}

t1 Triangle = Triangle{3, 4, 5}

c1 Circle = Circle{4}

var s1 Shape

s1 = t1

s1.peri(); s1.area(); // 但不能写s1.a, s1.b, s1.c

 

var s2 Shape

s2 = c1

s2.peri(); s2.area(); // 但不能写s2.r

 

也可以写一个方法

func testShape(s Shape) {}

testShape(t1)

testShape(c1)

testShape(s1)

 

 

 

instance, ok := 接口对象.(实际类型)

func getType (s Shape) {

if ins, ok := s.(Triangle) ; ok {

  fmt.Println(三角形的三边是", ins.a, ins.b, ins.c)

} else 

if ins, ok := s.(Circle) ; ok {

  fmt.Println(原型的半价是", ins.r)

}

}

补充1:可以使用指针。

补充2:使用switch方法 

 

 

 

 

8,接口嵌套

接口C 继承 接口A 和 接口B,结构体实现A和B的方法和接口C的方法。

var cat Cat = Cat{}

var a1 A = cat

var b1 B = cat

var c1 C = cat

如果Cat想实现C,必须实现A和B

 

7,空接口

type A interface {}

type Cat struct { color string }

type Person { name string  age int}

var a1 A = Cat{"花猫"}

var a2 A = Person{"往", 30}

var a3 A = "haha"

var a4 A = 100

 

func test1(a A) {} //可以接受任意类型的参数

func test2(a interface {}) {} //可以接受任意类型的参数

 

map1 := make(map[string]interface{})

map1["name"] = "李小花"

map1["age"] = 30

 

slice1 := make([]interface{}, 0, 10)

slice1 = append(slice1, a1, a2, a3, a4, 100, "abc")

 

6,接口

意义:解耦合。语言设计者说:接口设计具体突破性

go中接口是一组方法签名。当某个类型为实现了接口中所有方法,它被称为实现接口。

go中接口和类型的实现关系是非侵入式的,其他语言是显示定义 Class Mouse implements USB {}

多态比继承还重要。

动物Animal - Cat(color)和Dog(lookDoor())

对于狗的实例,既可以作为狗,也可以作为动物。

当作为动物实例时(接口的实例),不能访问狗的方法

 

用法:

1)一个函数如果接受接口类型作为参数,实际上可以传入任意实现类型对象作为参数。

Animal是接口,则可以传入Cat或Dog,则

var a Animal

a = cat //cat := Cat{} Cat的实例,则a可以调用Cat的方法。同理如果是a = dog,则可以调用Dog的方法。

 

2)定义一个类型为接口乐信,实际上可以赋值为任意实现类的对象。

var arr[3] USB

arr[0] = m1;//鼠标实例  m1 := Mouse{"罗技小红"}

arr[1] = f1;//u盘实例  f1 := FlashDisk{"闪迪64G"}

 

鸭子类型:

 

 

1)当需要接口类型的对象时,可以使用任意实现类对象代替。

2)接口对象不能访问实现类中的属性。

 

5,继承中的方法

子类自定义新方法

子类覆盖父类方法

 

 

4,方法

用结构体模拟面向对象变成。涉及概念:匿名字段(把结构体作为父结构体的字段),变量提升,方法。

模拟继承性:用匿名字段 用 type Student { Book } 。这样可以直接访问父类的字段和方法。 is a关系

模拟聚合关系:用 type Student { book * Book } 是has a,访问的时候子类无法直接访问父类,而是要通过book来访问。has a关系。

 

func (w Worker) funcName() () {}

w是Worker的实例,而且是值传递。

 

func (p *Worker) printInfo () {}

func (p *Cat) printInfo() {}

方法名不一样,但是各调各的。

为什么要设计方法?

不是纯面向对象。方法是实现类行为的方法,某一类别有的行为功能,需要接受指定的接收者调用

方法名可以相同,只要接收者不同就可以。

 

3,结构体嵌套

type Person struct {

  name string

  age int

  address Address

}

这才是灵魂所在。

s2 := Student {name:"", age:18,  book:Book{bookName:"", price: 89.7}}

结构体嵌套需要传递指针。

type Student struct {

  name string

  age int

  book *Book

}

不再是值复制,而是地址传递。这才是我们需要的。

 

2,结构体的匿名字段

匿名函数

匿名结构体

s2 := struct {

  name string

  age int

} {

  name: "李四"

  age: 19

}

s2.name, s2.age也能正常访问。

由于定义结构体就是要复用,而匿名结构体不能复用,所以意义不大,不常用,知道就行了。

 

type Worker struct {

  name string

  age int

}

w1 := Worker{name:"小王", age: 30}

type Worker struct {

  string

  int

}

w2 := Worker{"小王", 30} // 这样也可以

默认把类型当做名字了。

但匿名字段类型不能重复,即不能有两个字符串类型。否则会冲突。

 

还有一个用法:把另一个结构体当做匿名字段。

 

 

 

1,结构体的指针

var pp1 *Person

p1:=Person{"","", "",}

pp1 = &p1; 修改

new方式创建的就是指针。

pp3 := new(int) // 打印pp3和*pp3(pp3的内容)

 

posted @ 2020-12-13 16:52  走走停停走走  Views(340)  Comments(0Edit  收藏  举报