golang学习笔记——接口经典面试题 value receivers与pointer receiver

下面的代码是一个比较好的面试题

请问下面的代码是否能通过编译?

package mainimport "fmt"type People interface {Speak(string) string
}type Student struct{}func (stu *Student) Speak(think string) (talk string) {if think == "sb" {talk = "你是个大帅比"} else {talk = "您好"}return
}func main() {var peo People = Student{}think := "bitch"fmt.Println(peo.Speak(think))
}

编译输出

 cannot use Student{} (value of type Student) as People value in variable declaration: Student does not implement People (method Speak has pointer receiver)

答案

答案是不能,提示Stduent does not implement People (Speak method has pointer receiver),
修正方法是var peo People = &Stduent{},赋值为指针

在Go语言中,函数和方法是不一样的,函数是没有接收者的,而方法是有接收者的,属于某个结构体

接受者有两种:value receivers(按值传递),pointer receivers(按指针传递,可能改变传入的参数)

之前看到有地方解释道:pointer receivers的方法既能传值也能传指针,包含了value receivers的方法。

这个理解是错误的。

从这道题来看不是这样的,value receivers和pointer receivers是有明确区分的,people interface是value receivers,而student实现了pointer receivers的speak方法,所以student没有实现peple。

事实上pointer receivers的方法只是将m.speak()自动转换为(&m).speak(),这点官方的go tour中就有提到,go编译器帮你省去了取地址的一步。

Golang FAQ

Should I define methods on values or pointers?

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value

For programmers unaccustomed to pointers, the distinction between these two examples can be confusing, but the situation is actually very simple. When defining a method on a type, the receiver (s in the above examples) behaves exactly as if it were an argument to the method. Whether to define the receiver as a value or as a pointer is the same question, then, as whether a function argument should be a value or a pointer. There are several considerations.

First, and most important, does the method need to modify the receiver? If it does, the receiver must be a pointer. (Slices and maps act as references, so their story is a little more subtle, but for instance to change the length of a slice in a method the receiver must still be a pointer.) In the examples above, if pointerMethod modifies the fields of s, the caller will see those changes, but valueMethod is called with a copy of the caller’s argument (that’s the definition of passing a value), so changes it makes will be invisible to the caller.

By the way, in Java method receivers have always been pointers, although their pointer nature is somewhat disguised (and recent developments are bringing value receivers to Java). It is the value receivers in Go that are unusual.

Second is the consideration of efficiency. If the receiver is large, a big struct for instance, it may be cheaper to use a pointer receiver.

Next is consistency. If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used. See the section on method sets for details.

For types such as basic types, slices, and small structs, a value receiver is very cheap so unless the semantics of the method requires a pointer, a value receiver is efficient and clear.

我应该使用值还是指针定义方法

func (s *MyStruct) pointerMethod() { } // 指针方法
func (s MyStruct)  valueMethod()   { } // 值方法

对于不熟悉指针的程序员,很难理解这两个例子的区别,实际上这很简单。为类型定义方法时,接收者(上面例子中的 s)实际扮演的是方法的一个参数。判断使用值还是指针定义方法与判断使用值还是指针作为函数参数是相同的问题。有以下几点考虑。

首先,最重要的是,这个方法是否需要改变接收者?如果是,接收者必须是指针。(切片和映射扮演引用的角色,他们的情况更微妙,但如果要在一个方法中改变切片的长度,接收者依然必须是指针。)在上面的例子中,如果指针方法改变 s 的字段,调用者可以察觉那些更改,但是值方法使用的是调用者参数的一个副本(这就是值传递的定义),所以更改对调用者是不可见的。

顺便说一下,在 Java 中,方法的接收者永远是指针,尽管它们的指针是经过包装的(也有提议加入值接受者)。所以 go 的值接收者并不常见。

其次,是性能上的考虑。如果接收者是一个很大的结构体实例,使用指针接收者的开销要小很多。

然后是一致性的考虑。如果一个类型的某些方法必须是指针接收者,那么其他方法也应该如此,这样使用者才可以一致地调用该类型的方法集。查看 方法集 获取更多细节。

对于基础类型,切片,和小的结构体,值接收者的开销更小,所以除非方法在语义上需要指针接收者,使用值接收者会更高效和明确。

参考资料

接口经典面试题
go语言中的方法和interface的实现
Frequently Asked Questions (FAQ)
FAQ中文-我应该使用值还是指针定义方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/35207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何删除掉MySQL的多余的实例

删除 MySQL 的多余实例通常意味着我们希望卸载或停止某个 MySQL 服务器实例,并从系统中完全移除它。这通常涉及到几个步骤,包括但不限于停止服务、删除数据目录、卸载软件(如果适用)等。 1.基于 Linux 的系统上删除 MySQL 的多余实例 以下是一个详细的步…

运算符重载详解(完全版)

1.运算符重载 C为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字和参数列表,其返回值类型与参数列表都与普通的函数类似 函数名:关键字operator后面接需要重载的…

Interview preparation--Elasticsearch写入原理与调优

ES的写入过程 ES支持的写操作 create: create操作不同于put操作,put操作的时候如果当前put的数据存在则会被覆盖,如果put操作的时候加上操作类型create,如果数据存在则会返回失败,比如:PUT /pruduct/_cre…

【C/C++】告警及报错问题收集

告警及报错问题收集 1 warning 1.1 backslash and newline separated by space 原因:宏定义分行时,后不要有空格 2 error

Ubuntu20.04安装python2和python3及版本配置

Ubuntu20.04安装python2和python3及版本配置_ubuntu 20.04 python3-CSDN博客https://blog.csdn.net/pangc2014/article/details/117407413 >>>ubuntu 安装源码python2_mob649e8161c39d的技术博客_51CTO博客https://blog.51cto.com/u_16175489/7327966

大厂薪资福利篇第四弹:字节跳动

欢迎来到绝命Coding! 今天继续更新大家最关心的 大厂薪资福利系列! 往期分享: 福利开水喝不完?大厂薪资福利篇!美团 职场文化发源地?大厂薪资福利篇!阿里巴巴 给这么多!还能带宠物上…

MFC案例:自制工具条(Toolbar)按钮的小程序

程序目标:在基于对话框的MFC项目中,自制三个 Toolbar 按钮(用颜色区分,分别为红、绿、蓝);程序运行时,单击红色按钮显示一个红色的填充椭圆;再单击绿色按钮则进行清屏;最…

[hive] posexplode生成从去年一月一号,到本月的月时间表

生成从去年一月一号,到本月的月时间表 posexplode用法: lateral view 表别名 as 序号列名,数组中的元素的名 1、生成序列 SELECT time_stamp_fist_day_of_last_year,--去年第一天的时间戳numfrom(SELECTsplit(repeat_o,,) o_array,time_stamp_fist_da…

计组--指令系统--复习专用

文章目录 前言一、指令系统概述二、指令结构三、操作数类型四、指令操作码and扩展技术五、寻址方式1.指令寻址2.数据寻址 总结 前言 学无止境,笔勤不辍。今天,笔者分享关于计组中指令系统的复习知识点… 一、指令系统概述 有关机器指令的介绍&#xff…

用英文介绍纽约:NEW YORK, USA‘s MEGACITY

NEW YORK, USA’s MEGACITY | America’s Largest City Link: https://www.youtube.com/watch?vdzjQ-akB3BI&listPLmSQiOQJmbZ7TU39cyx7gizM9i8nOuZXy&index24 The story of New York City, America’s megalopolis. Summary Paragraph 1: The Historical Developm…

PostgreSQL 高级功能与扩展(九)

1. JSONB 数据类型与操作 1.1 JSONB 简介 JSONB 是 PostgreSQL 中的一种数据类型,用于存储 JSON 格式的数据,并提供高效的查询和索引功能。 1.1.1 创建 JSONB 列 CREATE TABLE json_data ( id SERIAL PRIMARY KEY, data JSONB ); 1.2 JSONB 查询与索…

Chrome插件:​Vue.js Devtools 高效地开发和调试

在现代前端开发中,Vue.js因其灵活性和性能优势,受到越来越多开发者的青睐。然而,随着项目规模的扩大,调试和优化变得愈发复杂。幸运的是,Vue.js Devtools的出现,为开发者提供了一套强大的工具集&#xff0c…

vue大屏适配方案

前言 开发过大屏的铁汁们应该知道,前期最头疼的就是大屏适配,由于大屏项目需要在市面上不是很常见的显示器上进行展示,所以要根据不同的尺寸进行适配,今天我将为大家分享的我使用的大屏适配方案,话不多说,直…

mongo基础操作总结

1.新搭建的环境没有安全验证,很容易被入侵,两个基础的安全模式: 1:一个改端口号,把默认27017改了,对方不知道端口号就没法入侵 2:建安全验证用户,先关闭安全验证,插入用…

Matlab|风光及负荷多场景随机生成与缩减

目录 1 主要内容 计算模型 场景生成与聚类方法应用 2 部分程序 3 程序结果 4 下载链接 1 主要内容 该程序方法复现了《融合多场景分析的交直流混合微电网多时间尺度随机优化调度策略》3.1节基于多场景技术的随机性建模部分,该部分是随机优化调度的重要组成部分…

轻松掌握:工科生如何高效阅读国际期刊和撰写论文(下)

⭐️我叫忆_恒心,一名喜欢书写博客的研究生👨‍🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支…

每日新闻掌握【2024年6月24日 星期一】

2024年6月24日 星期一 农历五月十九 大公司/大事件 阿里巴巴全球数学竞赛决赛试题公布,获奖选手名单将于8月公布 据阿里达摩院官微消息,北京时间6月22日24时,2024阿里巴巴全球数学竞赛决赛正式结束。本届决赛共有来自全球17个国家和地区的8…

源码解读:InternVL 1.5

源码地址:https://github.com/OpenGVLab/InternVL/tree/main/internvl_chat/internvl/model/internvl_chat 配置 在internvl_chat/internvl/model/internvl_chat/configuration_intern_vit.py 用InternVisionConfig类来设置类,用于初始化模型 num_channels=3,patch_size=1…

使用Spring Boot框架来生成HTML页面并返回给客户端

文章目录 1. 创建Spring Boot项目1.1 项目结构 2. 配置 pom.xml3. 编写代码3.1 创建主应用程序类3.2 创建数据模型3.3 创建数据仓库3.4 创建控制器3.5 创建HTML模板 4. 运行应用程序总结 下面是一个简单的Java实现,使用Spring Boot框架来生成HTML页面并返回给客户端…

透明屏幕的魅力:为何它如此受欢迎

在科技日新月异的今天,透明屏幕技术以其独特的魅力和广泛的应用前景,逐渐成为了科技领域的一颗璀璨明星。从智能手机、平板电脑到大型显示屏,透明屏幕技术以其前所未有的视觉体验和实用性,赢得了广大消费者的喜爱。 一、透明屏幕的…