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接口赋值与方法接收者问题

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值