golang 之 接口
interface是golang中的精华所在
定义
接口定义了对象的行为,当一个类型为接口中的所有方法提供定义时,它被称为接口。
具体指定类型应具有的方法,类型决定如何实现这些方法。
声明
type 接口名称 interface {
method1(参树列表) 返回值列表
method2(参树列表) 返回值列表
method3(参树列表) 返回值列表
}
interface 是为实现多态功能,意指可以根据类型的具体实现采用不同行为的能力。若一个类型实现了某个接口,所有使用这个接口的地方都可以支持这种类型。
注意:接口通常以 er 作为名称后缀,方法名是声明组成部分,但参数名可不同或省略。如果接口没有任何方法说明,那就是一个空接口(interface{}),空接口可被赋值为任何类型的对象,接口变量默认值是nil。
type worker interface {
job([]byte) error
}
使用场景
(很好的解释了为什么要使用接口) 假设公司有两个员工,一个普工,一个技术工,但是基本薪资相同,而技术工会多拿奖金。以此来计算公司为员工的总开支
package main
import "fmt"
type SalaryCaler interface {
CalculateSalary() int
}
// 普工
type Contract struct {
empId int
basicpay int
}
// 技术工
type Permnanent struct {
empId int
basicpay int
jiangjin int
}
func (p Permnanent) CalculateSalary() int {
return p.basicpay + p.jiangjin
}
func (C Contract) CalculateSalary() int {
return C.basicpay
}
// 总开支
func totalEx(s []SalaryCaler) {
expense := 0
for _, v := range s{
expense = expense + v.CalculateSalary()
}
fmt.Printf("总开支 %d ", expense )
}
func main() {
pem1 := Permnanent{1, 3000, 10000}
pem2 := Permnanent{2, 3000, 20000}
cem1 := Contract{3, 3000}
emplyees := []SalaryCaler{pem1, pem2, cem1}
totalEx(emplyees)
}
在上述例子中,也许会有这样的疑问:类型与接口的关系是什么样的?
类型与接口的关系
- 一个类型实现多个接口(彼此独立)
- 例如一个普通员工除了有工资还可以去消费。分别去定义为领工资lgzer 和消费 payer接口
// Lgzer 接口 type Lgzer interface { say() } // Payer 接口 type Payer interface { move() }实现方法
type pament struct { name string } type Lgzer interface { say() } // Payer 接口 type Payer interface { move() } func (p pament) Lgz() { fmt.Printf("%s发工资了\n", p.name) } func (p pament) Pay() { fmt.Printf("%s消费了\n", p.name) }
- 例如一个普通员工除了有工资还可以去消费。分别去定义为领工资lgzer 和消费 payer接口
- 多个类型实现同一个接口
- 例如在消费时,你可以消费,其他人也可以消费,而这时必须有一个pay方法
type Payer interface { pay() }具体实现如
type Payer interface { pay() } type ali struct { name string } type tenchrt struct { name string } func (a ali) pay() { fmt.Printf("%s 员工消费了", a.name) } func (t tenchrt) pay() { fmt.Printf("%s腾讯员工消费了\n", t.name) }
- 例如在消费时,你可以消费,其他人也可以消费,而这时必须有一个pay方法
接口的内部实现
一个接口可以认定为一个远足(类型, 值)在内部表示的。type是接口的基础具体类型, value是具体类型的值
package main
import "fmt"
type Test interface {
Tester()
}
type MyFloat float64
func (m MyFloat) Tester() {
fmt.Println(m)
}
func describe(t Test) {
fmt.Printf("interface 类型%T, 值: %v\n" ,t, t)
}
func main() {
var t Test
f := MyFloat(90.1)
t = f
describe(t)
t.Tester()
}
打印结果
interface 类型main.MyFloat, 值: 90.1 90.1
空接口
一开始就说过空接口,那么什么是空接口,即具有0个方法的接口称为空接口,它表示为interface{},由于没有方法,所以所有类型都能实现空接口。
package main
import "fmt"
func describe(i interface{}) {
fmt.Printf("Type = %T, value = %v \n", i, i)
}
func main() {
s := "hello"
i := 55
start := struct {
nane string
}{
"h",
}
describe(s)
describe(i)
describe(start)
}
输出对应结果
Type = string, value = hello
Type = int, value = 55
Type = struct { nane string }, value = {h}
有了空接口即会存在类型不确定的状态,这时就会有类型断言
类型断言
类型断言用于提取接口接口的基础值,语法 i.(T)
- i:表示类型为
interface{}的变量 - T:表示断言 i 可能是的类型。
一个接口值是由一个具体类型和具体类型的值来组成,有分别称为接口的动态类型。图分解如下

具体如
package main
import "fmt"
func findType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("v is string", v)
case int:
fmt.Println("v is int", v)
case float64:
fmt.Println("v is float", v)
default:
fmt.Println("不属于当前类型")
}
}
func main() {
findType("name")
findType(90.2)
findType(30)
}
虽然空接口在go中有广泛的应用,但也不能任意使用接口,否则只会增加不必要的性能消耗

浙公网安备 33010602011771号