面向对象的引入
Golang没有类(
class
),Go语言的结构体(struct
)和其他语言的类(class
)有同等地位,你可以理解Golang是基于struct
来实现面向对象(OOP)
的
具体对象
用户: 用户id(int|long),姓名(string),年龄(int),性别(bool|string)
结构体定义
方式一
package main
import "fmt"
type User struct{
//变量名大写可以让其他方法可以访问到这个属性
Id int
Name string
Age int
Sex string
}
func main(){
//创建结构体实例、对象、变量
var chen User
fmt.Println(chen)
}
如图说明Id:0
,Name:null
,Age:0
,Sex:null
方式二
var 实例名 对象类型 = 对象类型{}
package main
import "fmt"
type User struct{
//变量名大写可以让其他方法可以访问到这个属性
Id int
Name string
Age int
Sex string
}
func main(){
//创建结构体实例、对象、变量
var chen User = User{0,"admin",10,"保密"}
fmt.Println(chen)
}
方式三
返回结构体指针
var 实例名 *对象类型 = new(对象类型)
//赋值
(*实例名).属性 = value
//实例名.属性=value //go底层还是做了处理: 实例名.属性 转化 (*实例名).属性
package main
import "fmt"
type User struct{
//变量名大写可以让其他方法可以访问到这个属性
Id int
Name string
Age int
Sex string
}
func main(){
//创建结构体实例、对象、变量
var chen *User = new(User)
(*chen).Id = 0
(*chen).Name = "admin"
(*chen).Age = 10
(*chen).Sex = "保密"
fmt.Println(chen)
}
方法四
返回结构体指针
var 实例名 *对象类型 = &对象类型{}
结构体之间的转化
方法一
type 对象名1 struct{
Name string //同一属性
}
type 对象名2 struct{
Name string //同一属性
}
func main(){
var 实例名1 对象名1
var 实例名2 对象名2
实例名1 = 对象名1(实例名2)
}
package main
import "fmt"
type User struct{
//变量名大写可以让其他方法可以访问到这个属性
Name string
}
type Person struct{
Name string
}
func main(){
//创建结构体实例、对象、变量
var u User
var p Person
u = User(p)
fmt.Println(u)
}
方法二
结构体type重新定义(相当于取别名); Golang认为是新数据类型,但相互间可以强转
type 对象名1 struct{
}
type 对象名2 对象名1 //重定义对象1为对象2
func main(){
var 实例名1 对象名1
var 实例名2 对象名2
实例名1 = 对象名1(实例名2) //重定义还是得强转
}
package main
import "fmt"
type User struct{
//变量名大写可以让其他方法可以访问到这个属性
Name string
}
type U User
func main(){
//创建结构体实例、对象、变量
var u User
var u1 U
u = User(u1)
fmt.Println(u)
}
方法的引入
方法是作用在指定的数据类型上,和指定的数据类型绑定;因此自定义类型都可以有方法,不仅仅是struct
声明
type 对象名 struct{
...
}
//func 方法名(){/*这个是函数,所以是函数名(这里为了判断)*/}
func (实例名 对象名) 方法名(){//这个是方法
}
(实例名 对象名): 体现出方法和对象有绑定关系
package main
import "fmt"
type User struct{
//变量名大写可以让其他方法可以访问到这个属性
Name string
}
func (u User) test() {
fmt.Println(u)
}
func main(){
//创建结构体实例、对象、变量
var u *User = &User{"我"}
u.test()
}
方法注意事项
- 结构体类型是值类型,在方法调用中,遵守值类型传递机制,是值拷贝传递方式
package main
import "fmt"
type User struct{
Name string;
}
func (u User) test(){
u.Name = "大佬们"
fmt.Println(u.Name)//大佬们
}
func main(){
var u User
u.Name = "陈天羽"
u.test()
fmt.Println(u.Name)//陈天羽
}
意思是这个值的变化只有在方法中改变(值拷贝)
- 如程序员希望在方法中,改变结构体变量的值,可以通过结构体指针的方式来处理
package main
import "fmt"
type User struct{
Name string;
}
func (u *User) test(){ //指针类型User
(*u).Name = "大佬们好"
fmt.Println(u.Name)//大佬们好
}
func main(){
var u User
u.Name = "陈天羽"
(&u).test()//传递的是指针变量地址
fmt.Println(u.Name)//大佬们好
}
go语言可以简化
package main
import "fmt"
type User struct{
Name string;
}
func (u *User) test(){//对于前者来说就是改变了传入的对象值
u.Name = "大佬们好"
fmt.Println(u.Name)//大佬们好
}
func main(){
var u User
*u.Name = "陈天羽"
u.test()
fmt.Println(u.Name)//大佬们好
}
- Golang中的方法作用在指定的数据类型上的,和指定的数据类型绑定,因此自定义类型,都可以有方法,而不是仅仅是
struct
,比如int
,float
等都可以有方法
package main
import "fmt"
type integer int //给int类型起别名
func (i integer) print(){
fmt.Println("i = ",i)
}
func main(){
var i integer = 20
i.print()
}
如果方法里修改参数,得这么写
package main
import "fmt"
type integer int
func (i *integer) print(){
*i = 30
fmt.Println("i = ",i)
}
func main(){
var i integer = 20
i.print()
fmt.Println(i)
}
方法和函数的区别
调用方式不一样
函数
调用方法:函数名(实参列表)
(包调用除外包名.函数名(实参)
)方法
的调用方式: 方法绑定的类型.方法名(实参列表)
普通函数&方法
- 对于
普通函数
。接收者为值类型时,不能将指针数据直接传递,反之亦然 - 对于
方法
(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以
实例指定字段值
type Stu struct{
Name string
Age int
}
//第一种
var stu1 = Stu{"名字",10}
//第二种
stu2 := Stu{"名字1",18}
//第三种: 指定字段值
var stu3 = Stu{
Name: "jack",
Age: 20
}
//第四种
stu4 := Stu{
Age: 20
Name: "mary"
}
总结
var 实例名 = 对象名{数据类型,...}
实例名 := 对象名{数据类型,...}
var 实例名 = 对象名{字段名:value,字段名:value,...}
实例名 := 对象名{字段名:value,字段名:value,...}
工厂模式(go中的构造函数)
Golang的结构体里面没有构造函数,通常可以使用工厂模式来解决这个问题
- 一个构造函数我们之前学的都会写成
type student struct{}
我们要在其他包中去实例化这个结构体,我们要把s
tudent写成S
tudent; 如果我们继续需要使用studnet
就要使用到工厂模式
初始化go.mod(shell)
go mod init 项目名(包名)
项目代码
./go.mod
module go_struct//go_struct:项目名(包名)
go 1.19
require (
com.chentianyu.learn/model v0.0.0
)
replace (
com.chentianyu.learn/model => ./model
)
./main.go
package main
import (
"fmt"
"com.chentianyu.learn/model"
)
func main() {
var stu1 = model.Student{
Name: "tom",
Age: 20,
}
fmt.Println(stu1)
}
./model/go.mod
module model//model:项目名(包名)
go 1.19
./model/model.go
package model
type Student struct{
Name string
Age int
}
我希望我的结构体是小写的(私有)
./model/model.go
package model
type student struct{
Name string
Age int
}
//因为student结构体首字母小写,因此是只能使用在当前的包下
//我们通过工厂模式来解决这个问题
func NewStudent(n string,a int) *student{
return &student{
Name: n,
Age: a,
}
}
./main,go
package main
import (
"fmt"
"com.chentianyu.learn/model"
)
func main() {
//当student首字母小写,我们可以通过工厂模式来解决(其实调用了一个public的方法)
var stu1 = model.NewStudent("tom~",20)
fmt.Println(stu1) //&{...}
//fmt.Println(*stu1)//取值
//fmt.Println(stu1.Name)//编译器底层对访问字段的时候会在前面会加上'*':(*stu1).Name
}
字段有小写
./model/model.go
package model
type student struct{
name string
age int
}
//因为student结构体首字母小写,因此是只能使用在当前的包下
//我们通过工厂模式来解决这个问题
func NewStudent(n string,a int) *student{
return &student{
name: n,
age: a,
}
}
func (s *student) GetName() string {
return s.name
}
func (s *student) GetAge() int {
return s.age
}
./main,go
package main
import (
"fmt"
"com.chentianyu.learn/model"
)
func main() {
//当student首字母小写,我们可以通过工厂模式来解决(其实调用了一个public的方法)
var stu1 = model.NewStudent("tom~",20)
fmt.Println(stu1) //&{...}
fmt.Println(stu1.GetName())
}
面向对象编程思想 - 抽象
golang与传统的
oop(面向对象)语言
不太一样
什么是抽象?
我们在定义一个
结构体
时候,实际上就是把一类事物的共有属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象
一个实例(一个银行账户)
- 属性/字段
- 账号
- 密码
- 余额
行为/方法
- 存款
- 取款
- 查询
代码实现
属性/字段
type Account struct {
No string
Pwd string
Balance float64
}
行为/方法(存款)
//存款
func (account *Account) SaveMoney(money float64, pwd string){
//比对输入的密码是否正确
if pwd != account.Pwd {
fmt.Println("你输入的密码不正确")
return
}
//查看存款金额是否正确(不为负数和0)
if money <= 0 {
fmt.Println("你输入的金额不正确,小于等于0")
return
}
account.Balance += money
fmt.Println("存款成功")
}
行为/方法(取款)
//取款
func (account *Account) WithDraw(money float64, pwd string){
//比对输入的密码是否正确
if pwd != account.Pwd {
fmt.Println("你输入的密码不正确")
return
}
//查看取款金额是否正确(不为负数和0+不能大于存款的金额)
if money <= 0 || money > account.Balance{
fmt.Println("你输入的金额不正确,小于等于0")
return
}
account.Balance -= money
fmt.Println("取款成功")
}
行为/方法(查询)
//查询余额
func (account *Account) Query(pwd string){
if pwd != account.Pwd {
fmt.Println("你输入的密码不正确")
return
}
fmt.Printf("你的账号:%v你的余额:%v\n",account.No,account.Balance)
}
测试
/*
//有go.mod
package main
import (
// "fmt"
"com.chentianyu.learn/abs"
)
func main() {
account := go_abs.Account{
No: "chen",
Pwd: "666",
Balance: 100,
}
//查询金额
account.Query("666")
}
*/
package main
import (
"fmt"
)
type Account struct {
No string
Pwd string
Balance float64
}
//存款
func (account *Account) SaveMoney(money float64, pwd string){
//比对输入的密码是否正确
if pwd != account.Pwd {
fmt.Println("你输入的密码不正确")
return
}
//查看存款金额是否正确(不为负数和0)
if money <= 0 {
fmt.Println("你输入的金额不正确,小于等于0")
return
}
account.Balance += money
fmt.Println("存款成功")
}
//取款
func (account *Account) WithDraw(money float64, pwd string){
//比对输入的密码是否正确
if pwd != account.Pwd {
fmt.Println("你输入的密码不正确")
return
}
//查看取款金额是否正确(不为负数和0+不能大于存款的金额)
if money <= 0 || money > account.Balance{
fmt.Println("你输入的金额不正确,小于等于0")
return
}
account.Balance -= money
fmt.Println("取款成功")
}
//查询余额
func (account *Account) Query(pwd string){
if pwd != account.Pwd {
fmt.Println("你输入的密码不正确")
return
}
fmt.Printf("你的账号:%v你的余额:%v\n",account.No,account.Balance)
}
func main() {
account := Account{
No: "chen",
Pwd: "666",
Balance: 100,
}
//查询金额
account.Query("666")
}
如果修改密码
//查询金额
account.Query("66666")
存钱
//存入钱
account.SaveMoney(200.0,"666")
//存款后查询
account.Query("666")
封装 - 面向对象
在folang中没有特别强调要封装,
golang本身对面向对象特性做了简化
封装实现步骤
- 将结构体、字段(属性值)的首字母小写,其他包不能使用
- 给结构体所在的包提供一个工厂模式的函数(就是大写(public)函数,返回一个结构体(不可导出)),函数首字母大写(类似一个构造函数)
- 提供一个首字母大写的
Set
方法
func (var 结构体类型名) SetXxx(参数列表)(返回值列表){
//可以加入业务逻辑
var.字段 = 参数
}
快速入门(封装)
./go.mod
module go_fengzhuang
go 1.19
require (
com.chentianyu.learn/person v0.0.0
)
replace (
com.chentianyu.learn/person => ./person
)
./main.go
package main
import (
"fmt"
"com.chentianyu.learn/person"
)
func main(){
p := person.NewPerson("陈")
fmt.Println(p)
}
./person/go.mod
module person
go 1.19
./person/person.go
package person
import (
"fmt"
)
type person struct{
Name string
age int
sal float64
}
//写一个工厂模式函数(构造函数)
func NewPerson(name string) *person {
return &person {
Name : name,
}
}
//为了访问age和sal,需要编写getter和setter
func (p *person) GetAge() int{
return p.age
}
func (p *person) SetAge(age int){
if age > 0 && age < 150 {
p.age = age
}else {
fmt.Println("年龄范围不正确")
}
}
func (p *person) GetSal() float64{
return p.sal
}
func (p *person) SetSal(sal float64){
if sal > 3000 && sal <= 30000 {
p.sal = sal
}else {
fmt.Println("薪水范围不对")
}
}
./main.go
package main
import (
"fmt"
"com.chentianyu.learn/person"
)
func main(){
p := person.NewPerson("陈")
p.SetAge(18)
p.SetSal(5000)
fmt.Println(p)
}
继承 - 面向对象
继承的引出
package main
import (
"fmt"
)
//小学生
type XiaoXueStudent struct {
Name string
Age int
Score int
}
//显示成绩
func (x *XiaoXueStudent) ShowInfo(){
fmt.Printf("学生名:%v,年龄:%v,成绩:%v\n",x.Name,x.Age,x.Score)
}
//修改成绩
func (x *XiaoXueStudent) SetScore(score int){
x.Score = score
}
func (x *XiaoXueStudent) testing(){
fmt.Printf("小学生正在考试中....\n")
}
func main() {
//测试
jack := &XiaoXueStudent{
Name: "jack",
Age: 10,
}
jack.testing()
jack.SetScore(95)
jack.ShowInfo()
}
我们再构建一个大学生
对比之前创建的小学生
//小学生
type XiaoXueStudent struct {
Name string
Age int
Score int
}
//大学生
type CollegeStudent struct{
Name string
Age int
Score int
}
除了结构体名称,其余属性都是一样
继承基本语法
继承可以解决代码复用
案例
type 结构体名1 struct{
Name string
Price int
}
type 结构体名2 struct{
结构体名1//这里就是嵌套一个匿名结构: 结构体名1
Writer string
}
用继承基本语法重建学生结构体
package main
import (
"fmt"
)
//学生
type Student struct {
Name string
Age int
Score int
}
//小学生
type XiaoXueStudent struct {
Student//stu Student //嵌入了Student的匿名结构体
}
//大学生
type CollegeStudent struct{
Student//stu Student //嵌入了Student的匿名结构体
}
//显示成绩
func (s *Student) ShowInfo(){
fmt.Printf("学生名:%v,年龄:%v,成绩:%v\n",s.Name,s.Age,s.Score)
}
//修改成绩
func (s *Student) SetScore(score int){
s.Score = score
}
func (s *Student) testing(){
fmt.Printf("学生正在考试中....\n")
}
func main() {
//测试
var xxs = &XiaoXueStudent{}
xxs.Student.Name = "tom~"
xxs.Student.Age = 8
xxs.Student.testing()
xxs.Student.SetScore(70)
xxs.Student.ShowInfo()
}
继承的深入探讨
type A struct{
Name string
}
type B struct{
A
}
func main(){
}
- 当我们直接通过b访问字段或方法时直接执行流程:
b.Name
- 编译器会看b对应的类型有没有
Name
如果有直接调用B类型的Name字段 - 如果没有就会去B中嵌入的匿名结构体A中有没有声明
Name
字段,如果没有继续查找,如果都找不到则会报错 - 结构体嵌套俩个(或者多个)匿名结构体,如俩个匿名函数结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时,就必须明确指定匿名结构体名字,否则会报错。【举例说明】
type A struct{
Name string
Age int
}
type B struct{
Name string
score int
}
type C struct{
A
B
//Name string
}
type D struct{
a A //有名结构体
}
func main(){
var c C
c.A.Name = "tom"
var d D
//d.Name = "jack" //会报错
d.a,Name = "jack"
}
多重继承
为了保证代码的简洁性,建议尽量不使用多重继承
type A struct{...}
type B struct{...}
type C struct{
A
B
}
c := C{A{},B{}}
接口(interface) – 面向对象
在golang中多态特性主要是通过接口来体现的(接口是用来减少耦合的)
接口随处可见,比如
接口快速入门
定义接口
type 接口名 interface{
接口方法1()
接口方法2()
}
实现接口
type 结构体名 struct{}
func (结构体变量名 结构体名) 接口方法1(){
//实现
}
func (结构体变量名 结构体名) 接口方法2(){
//实现
}
type 结构体名 struct{}
func (结构体变量名 结构体名) 方法名(接口方法变量名 接口方法){
//实现
//接口方法变量名.接口方法
}
案例
package main
import "fmt"
//声明/定义一个接口
type Usb interface{
//接口的俩个方法
Start() //自定义方法
Stop() //自定义方法
}
//手机结构体
type Phone struct{}
func (phone Phone) Start(){
fmt.Println("手机开始充电")
}
func (phone Phone) Stop(){
fmt.Println("手机结束充电")
}
//相机
type Camera struct{}
func (c Camera) Start(){
fmt.Println("相机开始充电")
}
func (c Camera) Stop(){
fmt.Println("相机结束充电")
}
//电脑
type Computer struct{}
//只要实现Usb接口(所谓实现Usb接口,就是指实现了Usb接口声明所有方法)
func (computer Computer) Working(usb Usb){ //这个usb就体现出了多态:根据传入的值不同,之也不相同
usb.Start()
usb.Stop()
}
func main(){
//测试
//先创建结构体变量
computer := Computer{}
phone := Phone{}
// camera := Camera{}
//关键点
computer.Working(phone)
/* fmt.Println("==================")
computer.Working(camera) */
}
总结
以上代码说明的一点是,定义一个接口,里面的方法,要实现这个接口可以结构体实现接口里面的方法
接口的基本介绍
interface
类型可以定义一组方法,但是这些方法不需要实现。并且interface
不能包含任何变量。到某个自定义类型(比如type A struct
)要使用的时候,再根据情况把这些方法写出来
基本语法
type 接口名 interface {
method1(参数列表)返回值列表
method2(参数列表)返回值列表
...
}
//接口实现
type 结构体名 struct{}
func (结构体名) method1(参数列表)返回值列表{
//方法的method1(参数列表)返回值列表和接口的method1(参数列表)返回值列表要保持完全一致
}
接口语法说明
- 接口里面的所有方法都不能有方法体:
method1(参数列表)返回值列表{}(X)
; 接口方法都是没有实现方法的。接口体现了程序的设计思想多态和高聚低耦合的思想 - Golang中的接口,不需要显式的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口。因此:
golang中没有implements这个关键字
(只要interface中的方法实现了就可以)
接口特点
如果接口中多出一个方法没实现
type Usb interface{
//接口的俩个方法
Start() //自定义方法
Stop() //自定义方法
Test()
}
//手机结构体
type Phone struct{}
func (phone Phone) Start(){
fmt.Println("手机开始充电")
}
func (phone Phone) Stop(){
fmt.Println("手机结束充电")
}
//电脑
type Computer struct{}
//只要实现Usb接口(所谓实现Usb接口,就是指实现了Usb接口声明所有方法)
func (computer Computer) Working(usb Usb){
usb.Start()
usb.Stop()
}
func main(){
//测试
//先创建结构体变量
computer := Computer{}
phone := Phone{}
computer.Working(phone)
}
Phone没有实现Usb(没有实现Test方法)
go接口应用场景说明
应用场景(一)
形参里面的类型是一个接口
应用场景(二)
- 自定义类型1 -实现-> 接口1
- 自定义类型2 -实现-> 接口1
- 自定义类型3 -实现-> 接口2
- 自定义类型4 -实现-> 接口2
- 自定义类型5 -实现-> 接口2,接口3
接口注意事项和细节
- 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
type AInterface{
Say()
}
//实现
type Stu struct{
Name string
}
func (s Stu) Say(){
fmt.Println("Stu Say()")
}
func main(){
var stu Stu //结构体变量,实现了Say() 实现了AInterface
var a AInterface = stu
a.Say()
}
- 接口中所有的方法都没有方法体,即都没有实现的方法
- 在golang中,一个自定义类型需要将某个接口所在的所有方法都实现,我们说这个自定义类型实现了该接口
- 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋值给接口类型
- 只要是自定义类型,就可以实现接口,不仅仅是结构体类型
type integer int
func (i intager) Say(){
fmt.Println("integer Say i =",i)
}
func main(){
var i integer = 10
var b AInterface = i
b.Say() // integer Say i = 10
}
- 一个自定义类型可以实现多个接口
type AInterface interface{
Say()
}
type BInterface interface{
Hello()
}
type AStruct struct{}
func (a AStruct) Say(){
}
func (a AStruct) Hello(){
}
- Golang接口中不能有任何变量
type AInterface interface{
//Name string(X)
Test1()
Test2()
}
- 一个接口(比如A接口)可以继承多个别的接口(比如B接口,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现
- interface类型默认是一个**指针(引用类型) **, 如果没有interface初始化就是用那么会输出
nil
10.空接口interface{}
没有任何方法,所以所有类型都实现了空接口
type T interface{}
type Stu struct{}
func main(){
var stu Stu
var t T = stu
var t2 interface{} = stu
var num1 float64 = 8.8
t2 = num1
t = num1
}
多态 – 面向对象
基本介绍
变量(实例)具有多种形态。面向对象的第三大特征,在Go语言,多态特征是通过接口实现的。可以按照统一的接口来调用不同的实现。这时接口变量就会呈现不同的形态。
快速入门
type Usb interface{
Start()
Stop()
}
type A struct{}
func (a A) Start(){}
func (a A) Stop(){}
type B struct{}
func (b B) Start(){}
func (b B) Stop(){}
type C struct{}
func (c C) Func1(usb Usb){
usb.Start()
usb.Stop()
}
接口体现多态特征
- 多态参数
以上的Usb既可以是手机变量,又可以是相机变量。就体现了Usb接口的多态
- 多态数组
案例: 给Usb数组中,存放Phone结构体和Camera结构体变量,Phone还有一个特有的方法
call()
type Usb interface{
Start()
Stop()
}
type Phone struct{}
func (p Phone) Start(){}
func (p Phone) Stop(){}
type Camera struct{}
func (c Camera) Start(){}
func (c Camera) Stop(){}
func main(){
var usbArr [3]Usb
usbArr[0] = Phone{}
usbArr[1] = Phone{}
usbArr[2] = Camera{}
fmt.Println(usbArr)
}
类型断言引出和基本使用
引出
如果说一个方法(
call()
)是一个结构体特有的,另一个结构体没有。但是俩者都实现了一个接口,不能直接使用接口名.方法
看一个需求
type Point struct{
x int
y int
}
func main(){
var a interface{}
var point Point = Point{1,2}
a = point //可以的,原因:a是空接口
//将a(空接口)赋给一个Point变量?
var b Point
b = a //报错,原因: 经过a=point后,a指向结构体Point,但是这个没有没有指向
fmt.Println(b)
}
解决方法
package main
import (
"fmt"
)
type Point struct{
x int
y int
}
func main(){
var a interface{}
var point Point = Point{1,2}
a = point
var b Point
b = a.(Point) //类型断言。a的确指向Point
fmt.Println(b)
}
基本介绍
类型断言,是由接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用到类型断言
var f float32
var x interface{}
x = f
y := x.(float32)//转成float32
待检测的类型断言
var f float32
var x interface{}
x = f
y := x.(float64)//error
所以这么写
package main
import (
"fmt"
)
type Point struct{
x int
y int
}
func main(){
var f float32
var x interface{}
x = f
//类型判断(带检测的)
/*y,ok := x.(float64)
if ok {
fmt.Println(y)
}else{
fmt.Println("error")
}*/
if y,ok := x.(float64); ok{
}else{
}
}
类型断言实践案例1
package main
import (
"fmt"
)
type Usb interface{
Start()
Stop()
}
type Camera struct{}
func (c Camera) Start(){
fmt.Println("camera start")
}
func (c Camera) Stop(){
fmt.Println("camera stop")
}
type Phone struct{}
func (p Phone) Start(){
fmt.Println("phone start")
}
func (p Phone) Stop(){
fmt.Println("phone stop")
}
func (p Phone) Call(){
fmt.Println("phone call")
}
type Computer struct{}
func (computer Computer) Working(usb Usb){
usb.Start()
if phone, ok := usb.(Phone); ok {
phone.Call()
}
usb.Stop()
}
func main(){
var phone = Phone{}
var camera = Camera{}
var computer = Computer{}
computer.Working(phone)
computer.Working(camera)
}
类型断言实践案例2
func Func1(items ...interface{}){
for i,x := range items {
switch x.(type){ //type是一个关键字,固定写法
case bool:
break
case float64:
break
case int,int64:
break
default:
break
}
}
}
package main
import "fmt"
func TypeJudge(items ...interface{}){
for i, x := range items{
switch x.(type) {
case bool:
fmt.Printf("第%v个参数是bool类型,值是%v\n",i , x)
break
case float32:
fmt.Printf("第%v个参数是float32类型,值是%v\n",i , x)
break
case int,int32,int64:
fmt.Printf("第%v个参数是整数类型,值是%v\n",i , x)
break
case string:
fmt.Printf("第%v个参数是string类型,值是%v\n",i , x)
break
default:
fmt.Printf("第%v个参数是不确定的类型,值是%v\n",i , x)
break
}
}
}
func main(){
var n1 float32 = 1.1
var n2 float64 = 2.3
var n3 int32 = 30
var name string = "tom"
address := "北京"
n4 := 300
TypeJudge(n1,n2,n3,name,address,n4)
}