GO 语言中神秘的函数传参问题

2021-09-18 17:30:15 +08:00
 cookgo

首先展示一下代码:

package main

import "fmt"

type Obj1 struct {

}

type Callback1 func(interface{})
type Callback2 func(*Obj1)

func handle1(a int,fn Callback1)  {
	//do nothing
}

func handle2(a int,fn Callback2)  {
	//do nothing
}

func logic(o *Obj1) {
	fmt.Println(o)
}

func main() {
	handle1(1,logic)
	handle2(2,logic)
}

为什么 handle1 函数会编译不通过,interface{}不是可以代表任意类型吗?

2943 次点击
所在节点    Go 编程语言
14 条回复
egen
2021-09-18 17:34:10 +08:00
cb1 cb2 的函数签名不一致
Trim21
2021-09-18 17:43:08 +08:00
就跟[]int 不能赋值[]interface{}一样...
AlbertGuo
2021-09-18 17:51:56 +08:00
interface{}我理解成一种类型,Callback1 和 logic 的参数是不同类型
MoYi123
2021-09-18 17:52:53 +08:00
一定要传的话只能这样写

type Callback1 interface{}

func handle1(a int, fn Callback1) {
o := reflect.ValueOf(&Obj1{})
reflect.ValueOf(fn).Call([]reflect.Value{o})
}
anyxchachapoly
2021-09-18 18:05:59 +08:00
建议再去好好读下 golang 官方指导,这明显你误解了 interface & type 的概念
iyear
2021-09-18 18:18:07 +08:00
未曾设想的道路 😂
yuanchao
2021-09-18 18:26:34 +08:00
interface{} 也是一种类型
cookgo
2021-09-18 18:54:32 +08:00
@MoYi123 用断言的方式效率应该比反射高吧
mcfog
2021-09-18 19:15:25 +08:00
go 语言厉害就厉害在朴素
1. 方法调用实参和形参类型要求是 assignable
https://golang.org/ref/spec#:~:text=arguments%20must%20be%20single-valued%20expressions%20assignable%20to%20the%20parameter%20types%20of%20F

2. assignable 规则
https://golang.org/ref/spec#Assignability
对于两边都是 func 来说这啊那啊的都不适用,就是要求 identical

3. type identical 规则
3.1 func 要 identical 必须出入参对应位置 identical
https://golang.org/ref/spec#:~:text=corresponding%20parameter%20and%20result%20types%20are%20identical%2C

3.2 interface 和*Obj 不 identical,因为一个是 interface type 另一个是 pointer type


ref/spec 虽然有点拗口,但又短又精髓,查起来非常容易
iceheart
2021-09-18 19:28:55 +08:00
肯定不行啊,interface 占 16 字节,结构体指针占 8 字节,C 语言这种都不行
Nzelites
2021-09-18 21:22:36 +08:00
你需要的大概是 handle(interface{})
然后里面再断言回来
masterclock
2021-09-18 22:28:27 +08:00
不神秘,没有“类型推导”,go 编译器只做最基础的事情,不要深入理解。
Typescript 类的语言能这么干,函数 auto variance
Scala 类的定义好 variance 也能干
liuhan907
2021-09-18 23:07:33 +08:00
其实就是 go 没有协变。
thinkingbullet
2021-09-20 12:00:53 +08:00
当直接调用函数和把函数作为参数调用是两种不同的情况,前者如果参数是 interface 类型则可以传递任意类型,后者需要把函数整体作为参数考虑,需要严格的类型对比(也就是函数签名完全一致),一个是 interface type 另一个是 pointer type

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/802817

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX