浅谈Golang的方法传递值应该注意的地方
作者:piperck 发布时间:2024-02-12 07:40:20
其实最近看了不少Golang接口以及方法的阐述都有一个地方没说得特别明白。就是在Golang编译隐式转换传递给方法使用的时候,和调用函数时的区别。
我们都知道,在我们为一个类型变量申明了一个方法的时候,我们可以使用类似于self.method来调用这个方法,而且无论你申明的方法的 * 是指针 * 还是值 * ,Golang都可以帮你隐式转换为正确的值供方法使用。
让我们来看一个例子:
package main
import "fmt"
type duration int
func (d *duration) pretty() string {
return fmt.Sprintf("Duration: %d", d)
}
func main() {
var kk duration
kk = 3
kk.pretty()
}
在这个例子中,创建了一个类型为duration的变量kk,并且duration这个类型上有指针 * 的方法pretty()这个时候无论你使用kk.pretty()还有使用(&kk).pretty()都会正确执行,并且就算 * 不是指针类型而是值类型,同上一样。Golang编译器会将你传入的值隐式转换为正确的传入对象。
这个不难理解,但是有一个跟他很像的特性,却会让这个问题变得很绕。那就是调用接口的时候出现的情况
同样我们来看一个例子:
package main
import (
"fmt"
)
type notifier interface {
notify()
}
type user struct {
name string
email string
}
func(u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}
func sendNotification(n notifier) {
n.notify()
}
func main() {
u := user{"Bill", "bill@xiachufang.com"}
sendNotification(&u)
}
这个例子就不是用类型直接调用自己的方法了,而是把自己当作参数传递给接口。让接口去执行对应方法。
这里注意,接口对于类型的要求就十分严格了,接口在神明的时候会指定,拥有哪些方法(这里的方法指 方法名, 方法参数,以及方法返回类型)。实现了这些方法就实现了这个接口。这里我们调用sendNotification这个方法需要传递进实现了notifier这个接口的变量做参数。查看notifier代码可以注意到,他实现了一个notify的方法。而我们的user实现了一个指针 * 的notify方法。但是这里注意,传递值必须遵守一个条件即:
如果接口实现方法,类型自己的实现使用的是值 * ,那么在传递值的时候无论使用指针还是值都可以。
如果接口实现方法,类型自己的实现使用的是指针 * ,那么在传递值的时候必须传递地址。
所以上面的例子, * 是指针 * ,我们必须传递地址,如果传递值则会报错。
那么是为什么这里又不能进行隐式转换了呢?
实际上是因为,编译器并不能总能自动获得一个值的地方,也就是说你传u,编译器不一定能知道u的地址是啥。。他可能没有办法帮你完成转换。
补充:Golang 数组(切片)的值传递与引用传递
Go语言中函数的参数都是按值进行传递的,即使参数是指针,也是指针的一个副本。习惯上把指针的函数参数称之为地址传参,即引用传递,而非指针的函数参数称为值传参
地址传参在大对象上效率比值传参好,在内部相当于用指针地址赋值,而不用复制整个对象
一、数组的值传递
Golang数组作为参数传入函数时,进行的是值传递,这里与Java数组的引用传递是不同的,示例如下
package main
import "fmt"
func main() {
arr := [8]int{}
for i := 0; i < 8; i++ {
arr[i] = i
}
fmt.Println(arr)
exchange(arr)
fmt.Println(arr)
}
func exchange(arr [8]int) {
for k, v := range arr {
arr[k] = v * 2
}
}
运行结果如下:
二、数组的引用传递
默认情况下Golang的数组传递是值传递,但当我们想要对传入的数组进行修改时,可以使用指针来对数组进行操作,如下
package main
import "fmt"
func main() {
arr := [8]int{}
for i := 0; i < 8; i++ {
arr[i] = i
}
fmt.Println(arr)
exchangeByAddress(&arr)
fmt.Println(arr)
}
func exchangeByAddress(arr *[8]int) {
for k, v := range *arr {
arr[k] = v * 2
}
}
运行结果如下:
三、切片的引用传递
Golang中的切片与Java中的ArrayList集合类似,进行的是引用传递
package main
import "fmt"
func main() {
slice := []int{1,2,3,4,5}
fmt.Println(slice)
exchangeSlice(slice)
fmt.Println(slice)
}
func exchangeSlice(slice []int) {
for k, v := range slice {
slice[k] = v * 2
}
}
运行结果:
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://www.cnblogs.com/piperck/p/6550019.html


猜你喜欢
- JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于JavaScript(Standard
- 问题你想将几个小的字符串合并为一个大的字符串解决方案如果你想要合并的字符串是在一个序列或者 iterable 中,那么最快的方式就是使用 j
- 推荐系统MostPopular算法的Python实现MostPopular 算法的 是指对每个用户都选择出当前流行度最高的Top-K个物品进
- 假设我们需要一个函数什么事都不干,只是抛出异常(在某些系统中有些handler就是干这事的),我们可以很直观的写出下面的代码:def fun
- 什么是php: PHP,是英文超级文本预处理语言Hypertext Preprocessor的缩写。PHP 是一种 HTML 内嵌式的语言,
- 一、问题起源 稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统
- 目录一、比较汽车性能二、比较不同城市近期天气状况雷达图是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多变量数据的图形方
- 我就废话不多说了,大家还是直接看代码吧~import numpy as np kernel = np.array([1, 1, 1, 2])
- 一、实战场景Flask 框架实现用户的注册,登录和登出。二、主要知识点flask_login 插件使用SQLAlchemy 基础操作用户基础
- 网站改版,如何改?如果只是设计、功能和栏目等的稍微变动,这些很简单,从技术 上说并没有多少难度。只是对于网站本身的发展来说,没有多大的作用,
- 本文实例讲述了PHP基于迭代实现文件夹复制、删除、查看大小等操作的方法。分享给大家供大家参考,具体如下:前面一篇 PHP递归实现文件夹的复制
- 大家知道,我们经常在linux或者windows需要用到mysql数据库,但是我们经常会犯一种特别低级的小错误,小编也时常会犯的错误,突然就
- 组合字面量组合字面量是最直接方式初始化Go对象,假设定义了Book类型,使用字面量初始化代码如下:type Book struct { &n
- 本文实例讲述了php实现用于计算执行时间的类。分享给大家供大家参考。具体如下:有了这个php类,计算函数或者一段代码的执行时间就简单了<
- 今天遇到了这样一个问题,使用matplotlib绘制热图数组中横纵坐标自然是图片的像素排列顺序,但是这样带来的问题就是画出来的x,y轴中坐标
- 本文实例为大家分享了python访问者模式代码,供大家参考,具体内容如下"""访问者模式""
- 最近用sysbench进行了较多的性能测试,也总结一下它的特点和用法和需要注意的事项。sysbench是一个多线程性能测试工具,可以进行CP
- 24小时内记录(即86400秒)$sql="Select video_id,count(id)as n FROM `rec_dow
- 本文实例讲述了Python类的继承、多态及获取对象信息操作。分享给大家供大家参考,具体如下:继承类的继承机制使得子类可以继承父类中定义的方法
- 本文实例讲述了Python实用库 PrettyTable。分享给大家供大家参考,具体如下:PrettyTable安装使用pip即可十分方便的