• golang 接口变量的赋值和方法的调用


    1、「方法」概念介绍

    带有接收者的函数称为方法,方法是 go 语言中一种替代面向对象的方式。函数内部可以使用接收者,使用完之后根据接收者的类型是值类型还是指针类型选择是否自动覆盖原接收者。

    可以随意安排函数定义的顺序,编译器会在执行前扫描每个文件。

    2、接口变量的赋值

    接口定义为一个方法的集合。方法包含实际的代码。换句话说,一个接口就是定义, 而方法就是实现。因此,接收者不能定义为接口类型,这样做的话会引起 invalid receiver type ... 的编译器错误。
    接收者类型必须是 T 或 *T,这里的 T 是类型名。T 叫做接收者基础类型或 简称基础类型。
    如果接收者是实现了接口定义申明的所有方法,那么称这个接收者实现了这个接口。

    2.1 方法的接收者是值类型

    当方法的接收者是值类型时,接口变量可以被赋值为指针类型或者值类型的接收者对象

    package main
    
    import (
    	"fmt"
    )
    
    type Producer interface {
    	send(string) error
    }
    
    type KafkaProducer struct {
    	topic string
    	name  string
    }
    
    // 接收者是值类型
    func (s KafkaProducer) send(msg string) error {
    	fmt.Printf("send %s to topic [%s]\n", msg, s.topic)
    	return nil
    }
    
    func main() {
    	var producer Producer
    	kafkaProducer := KafkaProducer{"like_topic", "kafkaProducer"}
    	producer = kafkaProducer
    	fmt.Printf("%T, %#v \n", producer, producer) // main.KafkaProducer, main.KafkaProducer{topic:"like_topic", name:"kafkaProducer"}
    	producer.send("hahha") // send hahha to topic [like_topic]
    
    	producer = &kafkaProducer
    	fmt.Printf("%T, %#v \n", producer, producer) // *main.KafkaProducer, &main.KafkaProducer{topic:"like_topic", name:"kafkaProducer"}
    	producer.send("hahha") // send hahha to topic [like_topic]
    }
    

    2.2 方法的接收者是指针(引用)类型

    当接收者是指针类型时,接口变量只能被赋值为指针类型的接收者对象,如果被赋值为了值类型的接收者对象,会有类似下面程序的报错Cannot use 'rocketProducer' (type RocketProducer) as the type Producer Type does not implement 'Producer' as the 'send' method has a pointer receiver

    package main
    
    import (
    	"fmt"
    )
    
    type Producer interface {
    	send(string) error
    }
    
    type RocketProducer struct {
    	topic string
    	name  string
    }
    
    // 接收者是指针类型
    func (s *RocketProducer) send(msg string) error {
    	fmt.Printf("send %s to topic [%s]\n", msg, s.topic)
    	return nil
    }
    
    func main() {
    	var producer Producer
    
    	rocketProducer := RocketProducer{"collection_topic","rocketProducer"}
    	producer = rocketProducer // Cannot use 'rocketProducer' (type RocketProducer) as the type Producer Type does not implement 'Producer' as the 'send' method has a pointer receiver
    	fmt.Sprintf("%T, %#v\n", producer, producer)
    
    	producer = &rocketProducer
    	fmt.Printf("%T, %#v \n", producer, producer) // *main.RocketProducer, &main.RocketProducer{topic:"collection_topic", name:"rocketProducer"}
    	producer.send("hahha") // send hahha to topic [collection_topic]
    }
    

    2.3 对象没有实现接口

    如果对象没有实现接口的方法,那么不能被赋值给接口变量,否则会有类似如下程序的报错Cannot use 'rabbitProducer' (type RabbitProducer) as the type Producer Type does not implement 'Producer' as some methods are missing: send(string) error

    package main
    
    import (
    	"fmt"
    )
    
    type Producer interface {
    	send(string) error
    }
    
    type RabbitProducer struct {
    	topic string
    	name  string
    }
    
    func main() {
    	var producer Producer
    	rabbitProducer := RabbitProducer{"share_topic", "rabbitProducer"}
    	producer = rabbitProducer // Cannot use 'rabbitProducer' (type RabbitProducer) as the type Producer Type does not implement 'Producer' as some methods are missing: send(string) error
    }
    

    3、方法调用

    接收者是指针则在方法修改对象的属性会影响原来的对象,如果接收者是对象,那么在方法中修改对象的属性不会影响原来的对象。跟上面的接口变量赋值略有不同,不管方法里的接收者是指针类型还是对象类型,都可以同时使用指针对象和值对象调用。golang 通过语法糖,使得值对象也能直接调用接收者为指针类型的方法。

    package main
    
    import "fmt"
    
    type KafkaProducer struct {
    	topic string
    	name  string
    }
    
    // 接收者是值类型
    func (s KafkaProducer) updateName(newName string) error {
    	s.name = newName
    	return nil
    }
    
    type RocketProducer struct {
    	topic string
    	name  string
    }
    
    // 接收者是指针类型
    func (s *RocketProducer) updateName(newName string) error {
    	s.name = newName
    	return nil
    }
    
    func main() {
    	kafkaProducer1 := KafkaProducer{"like_topic", "kafkaProducer"}
    	kafkaProducer1.updateName("aaa")
    	fmt.Printf("kafkaProducer1.name = %v\n", kafkaProducer1.name)
    
    	kafkaProducer2 := &KafkaProducer{"like_topic", "kafkaProducer"}
    	kafkaProducer2.updateName("bbb")
    	fmt.Printf("kafkaProducer2.name = %v\n", kafkaProducer2.name)
    
    	rocketProducer1 := RocketProducer{"collection_topic","rocketProducer"}
    	rocketProducer1.updateName("aaa")
    	fmt.Printf("rocketProducer1.name = %v\n", rocketProducer1.name)
    
    	rocketProducer2 := &RocketProducer{"collection_topic","rocketProducer"}
    	rocketProducer2.updateName("bbb")
    	fmt.Printf("rocketProducer2.name = %v\n", rocketProducer2.name)
    }
    

    输出

    kafkaProducer1.name = kafkaProducer
    kafkaProducer2.name = kafkaProducer
    rocketProducer1.name = aaa
    rocketProducer2.name = bbb
    

    参考golang杂记01-golang接口的赋值问题GO接口赋值与方法接收者问题

  • 相关阅读:
    在 WinForm 中打开页面采用POST方式传参http。可以多个参数传递,返回json字符串
    交换平台第二章:项目边界与架构设计(上)
    物理隔离下的数据交换平台难点解析与实践(一)
    十年风雨,一个普通程序员的成长之路(六)抉择与出发
    十年风雨,一个普通程序员的成长之路(五) 成长:得到与教训
    十年风雨,一个普通程序员的成长之路(四)深圳:积累与转折
    十年风雨,一个普通程序员的成长之路(三)铜陵:大雪与加班
    十年风雨,一个普通程序员的成长之路(二)外包:颠沛与流离
    十年风雨,一个普通程序员的成长之路(一)怀念:西安的小黑屋
    多数据源连接Oracle报错,linux熵池耗尽问题
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/16484755.html
Copyright © 2020-2023  润新知