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

发布于 1周前 作者 vueper 来自 Go语言

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

首先展示一下代码:

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{}不是可以代表任意类型吗?


更多关于Golang Go语言中神秘的函数传参问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

15 回复

cb1 cb2 的函数签名不一致

更多关于Golang Go语言中神秘的函数传参问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


就跟[]int 不能赋值[]interface{}一样…

interface{}我理解成一种类型,Callback1 和 logic 的参数是不同类型

一定要传的话只能这样写

type Callback1 interface{}

func handle1(a int, fn Callback1) {
o := reflect.ValueOf(&Obj1{})
reflect.ValueOf(fn).Call([]reflect.Value{o})
}

建议再去好好读下 golang 官方指导,这明显你误解了 interface & type 的概念

未曾设想的道路 😂

interface{} 也是一种类型

用断言的方式效率应该比反射高吧

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 虽然有点拗口,但又短又精髓,查起来非常容易

肯定不行啊,interface 占 16 字节,结构体指针占 8 字节,C 语言这种都不行

你需要的大概是 handle(interface{})
然后里面再断言回来

不神秘,没有“类型推导”,go 编译器只做最基础的事情,不要深入理解。
Typescript 类的语言能这么干,函数 auto variance
Scala 类的定义好 variance 也能干

其实就是 go 没有协变。

当直接调用函数和把函数作为参数调用是两种不同的情况,前者如果参数是 interface 类型则可以传递任意类型,后者需要把函数整体作为参数考虑,需要严格的类型对比(也就是函数签名完全一致),一个是 interface type 另一个是 pointer type

在Go语言中,函数传参并非特别“神秘”,而是遵循了明确的值传递(pass-by-value)机制。这里有几个关键点可以帮助你理解:

  1. 值传递:在Go中,当你将一个变量传递给函数时,实际上是传递了该变量的一个副本。这意味着函数内部对参数的修改不会影响到函数外部的变量。

  2. 指针传递:虽然Go默认是值传递,但你可以通过传递指针来实现引用传递的效果。传递指针允许函数访问并修改原始数据。这在使用大型结构体或切片时特别有用,因为这样可以避免复制整个数据结构带来的性能开销。

  3. 接口传递:Go的接口是非常灵活的,可以作为函数参数。接口底层也是值传递,但当你传递一个指向具体类型的指针时,你可以间接地修改原始数据。

  4. 注意事项:在使用指针作为函数参数时,要确保指针是有效的,避免空指针引用。此外,对于切片和映射(map),虽然它们看起来像是引用类型,但在函数内部重新分配切片或映射底层数组时,也会导致外部变量不再引用原来的数据。

总之,Go语言的函数传参机制是清晰且一致的,理解值传递和指针传递的区别,以及如何在适当的时候使用它们,是掌握Go语言编程的重要一环。希望这些解释能帮助你更好地理解Go语言中的函数传参问题。

回到顶部