The Go Programming Language
› http://golang.org/
› Go Playground
Go Projects
› Revel Web Framework
cookgo

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

  •  
  •   cookgo · Sep 18, 2021 · 3960 views
    This topic created in 1877 days ago, the information mentioned may be changed or developed.

    首先展示一下代码:

    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 replies  •  2021-09-20 12:00:53 +08:00
    egen
    egen
    Sep 18, 2021
    1
    cb1 cb2 的函数签名不一致
    Trim21
    Trim21
    Sep 18, 2021
    2
    就跟[]int 不能赋值[]interface{}一样...
    AlbertGuo
    AlbertGuo
    Sep 18, 2021
    3
    interface{}我理解成一种类型,Callback1 和 logic 的参数是不同类型
    MoYi123
    MoYi123
    Sep 18, 2021❤️1
    4
    一定要传的话只能这样写

    type Callback1 interface{}

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