• 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发工资了
        ", p.name)
        }
        
        func (p pament) Pay() {
        	fmt.Printf("%s消费了
        ", p.name)
        }
    • 多个类型实现同一个接口
      • 例如在消费时,你可以消费,其他人也可以消费,而这时必须有一个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腾讯员工消费了
        ", t.name)
        }
        

    接口的内部实现

       一个接口可以认定为一个远足(类型, 值)在内部表示的。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
    " ,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 
    ", 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中有广泛的应用,但也不能任意使用接口,否则只会增加不必要的性能消耗

  • 相关阅读:
    linux tftp 服务
    AtomicInteger
    深入理解JVM(三)——垃圾收集策略具体解释
    Android 虚拟现实(virtual reality)入门指南
    Java千百问_05面向对象(005)_接口和抽象类有什么差别
    postman发送json格式的post请求
    什么是Session分布式共享
    如何设计一个单点登录系统(3)?
    如何设计一个单点登录系统(2)?
    如何设计一个单点登录系统(1)?
  • 原文地址:https://www.cnblogs.com/flash55/p/12350502.html
Copyright © 2020-2023  润新知