V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
cookgo

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

  •  
  •   cookgo · Sep 18, 2021 · 3511 views
    This topic created in 1683 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
        1
    egen  
       Sep 18, 2021
    cb1 cb2 的函数签名不一致
    Trim21
        2
    Trim21  
       Sep 18, 2021
    就跟[]int 不能赋值[]interface{}一样...
    AlbertGuo
        3
    AlbertGuo  
       Sep 18, 2021
    interface{}我理解成一种类型,Callback1 和 logic 的参数是不同类型
    MoYi123
        4
    MoYi123  
       Sep 18, 2021   ❤️ 1
    一定要传的话只能这样写

    type Callback1 interface{}

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