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的内容)