go语言--面向对象

面向对象的引入

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{}

我们要在其他包中去实例化这个结构体,我们要把student写成Student; 如果我们继续需要使用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(面向对象)语言不太一样

什么是抽象?

我们在定义一个结构体时候,实际上就是把一类事物的共有属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象

一个实例(一个银行账户)
  • 属性/字段
  1. 账号
  2. 密码
  3. 余额

行为/方法

  1. 存款
  2. 取款
  3. 查询
代码实现

属性/字段

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本身对面向对象特性做了简化

封装实现步骤

  1. 结构体、字段(属性值)的首字母小写,其他包不能使用
  2. 给结构体所在的包提供一个工厂模式的函数(就是大写(public)函数,返回一个结构体(不可导出)),函数首字母大写(类似一个构造函数)
  3. 提供一个首字母大写的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(){
}
  1. 当我们直接通过b访问字段或方法时直接执行流程:b.Name
  2. 编译器会看b对应的类型有没有Name如果有直接调用B类型的Name字段
  3. 如果没有就会去B中嵌入的匿名结构体A中有没有声明Name字段,如果没有继续查找,如果都找不到则会报错
  4. 结构体嵌套俩个(或者多个)匿名结构体,如俩个匿名函数结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时,就必须明确指定匿名结构体名字,否则会报错。【举例说明】
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(参数列表)返回值列表要保持完全一致
}
接口语法说明
  1. 接口里面的所有方法都不能有方法体: method1(参数列表)返回值列表{}(X); 接口方法都是没有实现方法的。接口体现了程序的设计思想多态和高聚低耦合的思想
  2. 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
接口注意事项和细节
  1. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
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()
  
}
  1. 接口中所有的方法都没有方法体,即都没有实现的方法
  2. 在golang中,一个自定义类型需要将某个接口所在的所有方法都实现,我们说这个自定义类型实现了该接口
  3. 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋值给接口类型
  4. 只要是自定义类型,就可以实现接口,不仅仅是结构体类型
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
}
  1. 一个自定义类型可以实现多个接口
type AInterface interface{
  Say()
}
type BInterface interface{
  Hello()
}

type AStruct struct{}

func (a AStruct) Say(){
}

func (a AStruct) Hello(){
}
  1. Golang接口中不能有任何变量
type AInterface interface{
  //Name string(X)
  Test1()
  Test2()
}
  1. 一个接口(比如A接口)可以继承多个别的接口(比如B接口,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现
  2. 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()
}
接口体现多态特征
  1. 多态参数

以上的Usb既可以是手机变量,又可以是相机变量。就体现了Usb接口的多态

  1. 多态数组

案例: 给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)
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

结城明日奈是我老婆

支持一下一直热爱程序的菜鸟吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值