多用户商城网站建设公司,营销策划与运营培训,稿定设计手机版下载,ICO网站模板1. 接口
1.1 基本介绍
接口中到底应该定义些什么#xff1f; 在Go语言中#xff0c;接口是声明函数的集合#xff0c;但只有函数签名#xff0c;没有具体的功能。 属于是面向对象中#xff0c;行为的约束#xff0c;面向对象中的类有自己的属性#xff08;可以当成数据…1. 接口
1.1 基本介绍
接口中到底应该定义些什么 在Go语言中接口是声明函数的集合但只有函数签名没有具体的功能。 属于是面向对象中行为的约束面向对象中的类有自己的属性可以当成数据成员或字段、方法可以当成函数函数有自己的操作或行为如下代码
type 接口名称 interface {dog() // 方法1签名cat() // 方法2签名方法1 (参数列表1) 返回值列表1方法2 (参数列表2) 返回值列表2
}上面这个接口A要求实现者必须实现方法1和方法2就是命名函数时只能用接口中的函数名命名。 也就是说如果有谁声称实现了某某接口那就必须实现该接口中的所有方法。
1.2 使用接口注意事项
接口命名习惯在接口名后面加上er后缀。参数列表、返回值列表参数名可以不写。如果要在包外使用接口接口名应该首字母大写方法要在包外使用方法名首字母也要大写。接口中的方法应该设计合理不要太多甚至越少越好。
2. 接口实现
如果一个结构体实现了一个接口声明的所有方法就说结构体实现了该接口。 一个结构体可以实现多个接口。
2.1 实现单个接口
package mainimport fmt// 定义一个运动接口
type Sport interface {// Go倾向小接口只有一个方法都行run() // 跑步jump() // 跳跃
}// 该接口由人来实现
type Person struct {name stringage int
}// 实现接口
///实现接口方法1
func (*Person) run() {fmt.Println(跑步)
}///实现接口方法2
func (*Person) jump() {fmt.Println(跳跃)
}func main() {p1 : new(Person) // 创建一个新的指针实例减少数据拷贝次数p1.jump()p1.run()
}
调试结果
跳跃
跑步再来看一个特殊示例
package mainimport fmttype Sport interface {run() // 跑步jump() // 跳跃
}type Person struct {name stringage int
}func (*Person) run() {fmt.Println(跑步)
}func (*Person) jump() {fmt.Println(跳跃)
}// 我这里新加了一个成员方法请问Person结构体实现了Sport接口吗
// 当然实现了上面两个成员方法已经实现了Sport接口我当然可以继续定义Person结构体的其他方法。
func (t *Person) swim() {fmt.Println(游泳)
}func main() {p1 : new(Person)p1.jump()p1.run()p1.swim()
}
调试结果
跳跃
跑步
游泳2.1.1 把接口类型赋值给变量
package mainimport fmttype Sport interface {run()jump()
}type Person struct {name stringage int
}func (*Person) run() {fmt.Println(跑步)
}func (*Person) jump() {fmt.Println(跳跃)
}func (t *Person) swim() {fmt.Println(游泳)
}func main() {p1 : new(Person)p1.jump()p1.run()p1.swim()fmt.Println(-------------------)var a Sport p1 // 把接口类型赋值给变量该变量就是个接口类型的变量了fmt.Println(a)a.jump() // 可以直接调用接口中的方法a.run()
}
调试结果
跳跃
跑步
游泳
-------------------
{ 0}
跳跃
跑步3. 接口嵌入组合 除了结构体可以嵌套接口也可以。接口嵌套组合成了新接口。 type Reader interface {Read(p []byte) (n int, err error)
}
type Closer interface {Close() error
}
type ReadCloser interface {ReaderCloser
}这样写的好处就是如果需要同时调用Reader和Closer直接调用ReadCloser就行了。 4. 空接口
4.1 什么是空接口 在 Go 语言中空接口interface{}是一个没有方法的接口。这意味着任何类型都可以实现空接口或者说空接口可以匹配任意类型的数据因为它们不需要满足任何方法的要求。 空接口可以存储任何类型的值这使得它在需要存储未知类型数据时非常有用。 4.2 定义空接口
4.2.1 基本定义
func main() {var b interface{} // 空接口类型注意是空接口类型这部分interface{}表示数据类型var c any // 这样也行any是interface{}的别名鼠标移到any上能看到
}4.2.2 空接口和任意数据类型组合
func main() {var a 500var b interface{} // 空接口b的类型是接口类型但是个空接口// var b any // 或者这样声明更好理解any表示任意数据类型// 为什么b能等于a因为interface{}是空接口里面没有任何方法。// 换句话说不管什么类型都能实现空接口。b afmt.Printf(b的类型%T\nb的值%[1]v\n, b)fmt.Println(-----------------------------------)var c abcb cfmt.Printf(b的类型%T\nb的值%[1]v\n, b)
}
调试结果
b的类型int
b的值500
-----------------------------------
b的类型string
b的值abc4.3 为什么要用空接口 比如我有这样一个需求我需要一个容器该容器能存储任意类型的数据并且能够混装注意是能混装 这咋整呢用结构体吗不行结构体虽然能混装不同的数据类型但它有个前提必须要有明确的字段。 所以这种情况下只有空接口interface{}是最合适的。 var d []any{1, 2.1, true, abc}
// []interface{},表示数据类型后面的{}表示元素字面量定义
var e []interface{}{1, 2.1, true, abc}
fmt.Printf(d的类型%T|d的值%[1]v\n, d)
fmt.Printf(e的类型%T|e的值%[1]v\n, e)
调试结果
d的类型[]interface {}|d的值[1 2.1 true abc] // 返回值为任意数据类型的切片
e的类型[]interface {}|e的值[1 2.1 true abc]5. 接口类型断言
5.1 基本介绍 在 Go 语言中当你有一个接口变量时你可以通过 类型断言 来检查它实际存储的类型注意只能配合接口使用。 类型断言的基本语法是 变量.(数据类型)。 5.2 示例
5.2.1 基本使用
var a 500
var b interface{} a// v, ok : b.(int) 含义把b接口中存储的数据当成int可以吗
// 可以ok返回truev返回对应的值
// 不可以ok返回falsev返回对应数据类型的默认值int0,str: 空串
v, ok : b.(int)
fmt.Printf(v%v ok%v\n, v, ok)v1, ok1 : b.(string)
fmt.Printf(v%v ok%v\n, v1, ok1)
调试结果
v500 oktrue
v okfalse // 注意这里的v是空串5.2.2 结合if判断 string类型断言失败会返回空串但万一默认就是空串呢所以这里最好结合if一起使用判断ok的值来判断类型断言是否成功如下代码 var a 500
var b interface{} aif v, ok : b.(string); ok {fmt.Printf(断言成功v的类型为%T 值为%[1]v, v)
} else {fmt.Printf(断言失败v的类型为%T 值为%[1]v, v)
}
调试结果
断言失败v的类型为string 值为5.3 type-switch 当需要判断多个原始数据类型时写if的话需要写很长的代码这里可以使用type-switch来替代if更加简洁。 注意type-switch只能配合接口类型断言使用。 var a 500
var b interface{} a// b.(type)的意思是取b接口中数据的类型
switch b.(type) { // 这个b.(type)可以用变量接住值会赋值给该变量
case int:fmt.Println(int值,b)
case string:fmt.Println(string)
case bool:fmt.Println(bool)
case nil: // 在判断接口或指针类型时最好加上nil判断防止出现空接口或空指针fmt.Println(nil 空接口)
default:fmt.Println(其他)
}
调试结果
int值 5006. 接口输出格式化
6.1 普通方式格式化
先看一段代码
package mainimport (fmt
)type Sport interface {run()jump()
}type Person struct {name stringage int
}func (*Person) run() {fmt.Println(跑步)
}func (*Person) jump() {fmt.Println(跳跃)
}func (t *Person) swim() {fmt.Println(游泳)
}func main() {var p new(Person)fmt.Printf(%v\n, p)
}
调试结果
{name: age:0}可以看到上述代码默认输出格式看起来不太美观可以如下优化一下
package mainimport (fmt
)type Sport interface {run()jump()
}type Person struct {name stringage int
}func (*Person) run() {fmt.Println(跑步)
}func (*Person) jump() {fmt.Println(跳跃)
}func (t *Person) swim() {fmt.Println(游泳)
}func Print(p *Person) string {return fmt.Sprintf(我叫%s我的年龄是%d, p.name, p.age)
}func NewPerson(name string, age int) *Person {return Person{name, age}
}func main() {var p NewPerson(Tom, 21)fmt.Println(Print(p))
}
调试结果
我叫Tom我的年龄是216.2 方法格式化
package mainimport (fmt
)type Sport interface {run()jump()
}type Person struct {name stringage int
}func (*Person) run() {fmt.Println(跑步)
}func (*Person) jump() {fmt.Println(跳跃)
}func (t *Person) swim() {fmt.Println(游泳)
}func (p *Person) String() string {return fmt.Sprintf(我叫%s我的年龄是%d, p.name, p.age)
}func NewPerson(name string, age int) *Person {return Person{name, age}
}func main() {var p NewPerson(Tom, 21)fmt.Printf(%v\n, p)fmt.Printf(%v\n, p)fmt.Println(p)fmt.Print(p)
}
调试结果
我叫Tom我的年龄是21
我叫Tom我的年龄是21
我叫Tom我的年龄是21
我叫Tom我的年龄是21