V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
cookgo
V2EX  ›  Go 编程语言

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

  •  
  •   cookgo · 2021-09-18 17:30:15 +08:00 · 2943 次点击
    这是一个创建于 1161 天前的主题,其中的信息可能已经有所发展或是发生改变。

    首先展示一下代码:

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

    14 条回复    2021-09-20 12:00:53 +08:00
    egen
        1
    egen  
       2021-09-18 17:34:10 +08:00
    cb1 cb2 的函数签名不一致
    Trim21
        2
    Trim21  
       2021-09-18 17:43:08 +08:00
    就跟[]int 不能赋值[]interface{}一样...
    AlbertGuo
        3
    AlbertGuo  
       2021-09-18 17:51:56 +08:00
    interface{}我理解成一种类型,Callback1 和 logic 的参数是不同类型
    MoYi123
        4
    MoYi123  
       2021-09-18 17:52:53 +08:00   ❤️ 1
    一定要传的话只能这样写

    type Callback1 interface{}

    func handle1(a int, fn Callback1) {
    o := reflect.ValueOf(&Obj1{})
    reflect.ValueOf(fn).Call([]reflect.Value{o})
    }
    anyxchachapoly
        5
    anyxchachapoly  
       2021-09-18 18:05:59 +08:00
    建议再去好好读下 golang 官方指导,这明显你误解了 interface & type 的概念
    iyear
        6
    iyear  
       2021-09-18 18:18:07 +08:00
    未曾设想的道路 😂
    yuanchao
        7
    yuanchao  
       2021-09-18 18:26:34 +08:00
    interface{} 也是一种类型
    cookgo
        8
    cookgo  
    OP
       2021-09-18 18:54:32 +08:00
    @MoYi123 用断言的方式效率应该比反射高吧
    mcfog
        9
    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
        10
    iceheart  
       2021-09-18 19:28:55 +08:00 via Android
    肯定不行啊,interface 占 16 字节,结构体指针占 8 字节,C 语言这种都不行
    Nzelites
        11
    Nzelites  
       2021-09-18 21:22:36 +08:00
    你需要的大概是 handle(interface{})
    然后里面再断言回来
    masterclock
        12
    masterclock  
       2021-09-18 22:28:27 +08:00
    不神秘,没有“类型推导”,go 编译器只做最基础的事情,不要深入理解。
    Typescript 类的语言能这么干,函数 auto variance
    Scala 类的定义好 variance 也能干
    liuhan907
        13
    liuhan907  
       2021-09-18 23:07:33 +08:00 via Android
    其实就是 go 没有协变。
    thinkingbullet
        14
    thinkingbullet  
       2021-09-20 12:00:53 +08:00
    当直接调用函数和把函数作为参数调用是两种不同的情况,前者如果参数是 interface 类型则可以传递任意类型,后者需要把函数整体作为参数考虑,需要严格的类型对比(也就是函数签名完全一致),一个是 interface type 另一个是 pointer type
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2904 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 11:12 · PVG 19:12 · LAX 03:12 · JFK 06:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.