接口
package main
import "fmt"
//39
func main() {
/*
interface:在Go中,接口是一组方法签名
当某个类型为这个接口中的所有方法提供了方法的实现,它被称为实现接口
Go语言中,接口和类型的实现关系,是非嵌入式
1. 当需要接口类型的对象时,可以使用任意实现类对象代替
2. 接口对象不嫩访问实现类的属性
*/
//创建鼠标
m1 := Mouse{"小红"}
fmt.Println(m1.name)
//创建键盘
f1 := FlashDisk{"小黑"}
fmt.Println(f1.name)
testInterface(m1)
testInterface(f1)
var usb USB
usb = m1
usb.start()
usb.end()
// fmt.Println(usb.name) 没有name,为实现类特有
}
//1. 定义接口
type USB interface {
start() //USB开始工作
end() //USB结束工作
}
//实现类
type Mouse struct {
name string
}
type FlashDisk struct {
name string
}
func (m Mouse) start() {
fmt.Println(m.name,"鼠标准备就绪,可以工作。。。。")
}
func (m Mouse) end() {
fmt.Println(m.name,"鼠标结束工作,可以安全退出。。。。")
}
func (f FlashDisk) start() {
fmt.Println(f.name,"键盘准备就绪,可以工作。。。。")
}
func (f FlashDisk) end() {
fmt.Println(f.name,"键盘结束工作,可以安全退出。。。。")
}
//3. 测试方法
func testInterface(usb USB) {
usb.start()
usb.end()
}
接口类型
/*
接口类型:
解耦合
多态:
go语言通过接口模拟多态
一个接口的实现
1. 看成实现本身的类型,能够访问实现类中的属性和方法
2. 看成是对应接口类型,那就只能访问接口中的方法
接口得用法:
1. 一个函数如果接收接口类型作为参数,那么实际上可以传入该接口得
任意实现类型对象作为参数
2. 定义一个接口类型,实际上可以赋值为任意实现类得对象
鸭子类型:
*/
f1.deletedata() //小黑 U盘数据删除
// usb.deletedata() 无法访问
func (f FlashDisk) deletedata() {
fmt.Println(f.name,"U盘数据删除")
}
空接口
/*
空接口:不包含任何方法,正因为如此,所有的类型都实现了空接口
因此空接口可以存储任意类型得数值
print方法多用空接口接收任意类型数据
*/
var a1 A = Cat{"花猫"}
var a2 A = Person5{"王二狗",30}
var a3 A = "haha"
var a4 A = 100
fmt.Println(a1)
fmt.Println(a2)
fmt.Println(a3)
fmt.Println(a4)
test1(a1)
test1(a2)
test1(3.14)
test1("st")
//接口A是空接口,理解为待变任意类型
func test1(a A){
fmt.Println(a)
}
func test2(a interface{}) {
fmt.Println("------>",a)
}
//空接口
type A interface {
}
type Cat struct {
color string
}
type Person5 struct {
name string
age int
}
接口嵌套
/*
接口嵌套
*/
var cat Cat111 = Cat111{}
cat.test111()
cat.test222()
cat.test333()
var a111 AAA = cat
a111.test111()
var b111 BBB = cat
b111.test222()
var c111 CCC = cat
c111.test111()
c111.test222()
c111.test333()
var a222 AAA = c111
a222.test111()
type AAA interface {
test111()
}
type BBB interface {
test222()
}
type CCC interface {
AAA
BBB
test333()
}
type Cat111 struct {
//如果想实现接口C,那不止要实现接口C得方法,还要实现接口A、B得方法
}
func (c Cat111) test111() {
fmt.Println("test111()......")
}
func (c Cat111) test222() {
fmt.Println("test222()......")
}
func (c Cat111) test333() {
fmt.Println("test333()......")
}
接口断言
package main
import (
"fmt"
"math"
)
//40
func main() {
/*
接口断言
方式一:
1. instance := 接口对象.(实际类型) //不安全,会panic
2. instance,ok := 接口对象.(实际类型) //安全
方式二:
switch instance := 接口对象.(Type) {
case 实际类型1:
...
case 实际类型2:
...
...
}
*/
var t1 Triangle = Triangle{3,4,5}
fmt.Println(t1.peri())
fmt.Println(t1.area())
var c1 Circle = Circle{4}
fmt.Println(c1.peri())
fmt.Println(c1.area())
var s1 Shape
s1 = t1
fmt.Println(s1.peri())
fmt.Println(s1.area())
var s2 Shape
s2 = t1
fmt.Println(s2.peri())
fmt.Println(s2.area())
testShape(t1)
testShape(c1)
testShape(s1)
getType(t1)
getType(c1)
getType(s1)
var t2 *Triangle = &Triangle{3,4,2}
fmt.Printf("t2:%T,%p\n",t2,&t2)
getType(t2)
getType2(t2)
}
func getType2(s Shape) {
switch ins := s.(type) {
case Triangle :
fmt.Println("是三角型,三边:",ins.a,ins.b,ins.c)
case Circle:
fmt.Println("是圆形,半径是:",ins.radius)
case *Triangle:
fmt.Println("三角型结构体指针")
}
}
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.radius)
}else if ins,ok := s.(*Triangle);ok {
fmt.Printf("ins:%T,%p\n",ins,&ins)
fmt.Printf("ins:%T,%p\n",s,&s)
}else{
fmt.Println("我也不知道")
}
}
func testShape(s Shape) {
fmt.Printf("周长:%.2f,面积:%.2f\n",s.peri(),s.area())
}
//定义一个接口
type Shape interface {
peri() float64 //形状得周长
area() float64 //形状得面积
}
//定义实现类:三角型
type Triangle struct {
a,b,c float64
}
func (t Triangle) peri() float64 {
return t.a + t.b + t.c
}
func (t Triangle) area() float64 {
p := t.peri() / 2
s := math.Sqrt(p*(p-t.a)*(p-t.b)*(p-t.c))
return s
}
//圆形
type Circle struct {
radius float64
}
func (c Circle) peri() float64 {
return c.radius * 2 * math.Pi
}
func (c Circle) area() float64 {
return math.Pow(c.radius,2) * math.Pi
}
type关键字
package main
import (
"fmt"
"strconv"
)
//41
func main() {
/*
type:用于类型定义和类型别名
1. 类型定义:type 类型名 Type
2. 类型别名:type 类型名 = Type
*/
var i1 myint
var i2 = 100
i1 = 200
fmt.Println(i1,i2) //200 100
var name mystr
name = "王二狗"
var s1 string
s1 = "李小花"
fmt.Println(name,s1) //王二狗 李小花
//i1 = i2 Cannot use 'i2' (type int) as type myint in assignment
fmt.Printf("%T,%T,%T,%T\n",i1,i2,name,s1) //main.myint,int,main.mystr,string
res1 := fun8()
fmt.Println(res1(10,20))
//别名
var i3 myint2
i3 = 1000
fmt.Println(i3)
i3 = i2
fmt.Println(i3)
fmt.Printf("%T,%T,%T\n",i1,i2,i3) //main.myint,int,int
}
//定义一个新的类型
type myint int
type mystr string
//定义哈数类型
type myfun func(int,int)(string)
func fun8() myfun {
fun := func(a,b int)string {
s := strconv.Itoa(a) + strconv.Itoa(b)
return s
}
return fun
}
//类型别名
type myint2 = int //不是重新定义新的数据类型,只是起了个别名,和int通用
package main
import "fmt"
//42
func main() {
/*
type:用于类型定义和类型别名
1. 类型定义:type 类型名 Type
2. 类型别名:type 类型名 = Type
*/
var s Student8
// s.name = "王二狗" //ambiguous selector s.name 混淆了
s.Person8.name = "王二狗"
// s.show() 混淆
}
type Person8 struct {
name string
}
func (p Person8) show() {
fmt.Println("------------",p.name)
}
//类型别名
type People = Person8
//func (p People) show() { //Method redeclared 'People.show' 重复定义
//
//}
type Student8 struct {
//嵌入两个结构体
Person8
People
}
//type MyDuration = time.Duration
//
//func (m MyDuration) SimpleSet() { //Cannot define new methods on non-local type 'time.Duration'
//
//}