【问题标题】:Golang Invalid Receiver Type in Method FuncGolang方法Func中的无效接收器类型
【发布时间】:2017-11-08 10:03:21
【问题描述】:

我正在尝试制作一个简单的包来将 SSH 命令发送到服务器。

我有以下代码:

type Connection *ssh.Client

func Connect(addr, user, password string) (conn Connection, err error) {
    sshConfig := &ssh.ClientConfig{
        User: user,
        Auth: []ssh.AuthMethod{
            ssh.Password(password),
        },
        HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),
    }

    conn, err = ssh.Dial("tcp", addr, sshConfig)
    return
}

func (conn Connection) SendCommand() ([]byte, error) {
    session, err := (*ssh.Client)(conn).NewSession()
    // ...
}

我的问题在于func (conn Connection) SendCommand() ([]byte, error)session, err := (*ssh.Client)(conn).NewSession() 这两行。

我无法从覆盖的Connection 类型中弄清楚如何使用可用于*ssh.Client 的方法。

我知道我需要进行一些转换,并且使用 ssh.Client(*conn).NewSession() 会起作用,但它会复制 *ssh.Client 的值,这似乎不是正确的方法。

在使用我的自定义 type Connection *ssh.Client 类型时,应该如何访问可用于 *ssh.Client 的方法?

【问题讨论】:

    标签: pointers go casting type-conversion


    【解决方案1】:

    您不能使用指针 TypeSpec 声明新类型。还声明一个新类型专门用于删除整个方法集,因此您不会拥有来自*ssh.Client 的任何原始方法。

    您想要的是通过将*ssh.Client 嵌入到您自己的结构类型中来使用组合:

    type Connection struct {
        *ssh.Client
    }
    
    func Connect(addr, user, password string) (*Connection, error) {
        sshConfig := &ssh.ClientConfig{
            User: user,
            Auth: []ssh.AuthMethod{
                ssh.Password(password),
            },
            HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),
        }
    
        conn, err = ssh.Dial("tcp", addr, sshConfig)
        if err != nil {
            return nil, err
        }
    
        return &Connection{conn}, nil
    }
    
    func (conn *Connection) SendCommand() ([]byte, error) {
        session, err := conn.NewSession()
        // ...
    }
    

    【讨论】:

    • 完美运行。 return Connection{conn}, nil 应改为 return &Connection{conn}, nil
    【解决方案2】:

    这是我能想到的最好的:

    type Connection ssh.Client
    
    func (conn *Connection) SendCommand() ([]byte, error) {
        (*ssh.Client)(conn).NewSession()
    

    请注意,我已将类型更改为 not 为指针类型(但后来我为SendCommand 制作了指针接收器)。我不确定有什么方法可以创建一个以指针类型作为接收器的函数。

    【讨论】:

    • 这行得通,这是我在等待答案时使用的方法,但我的 linter 给我一条消息说call of Connection copies lock value ssh.Client
    • 它在抱怨哪一行?
    • play.golang.org/p/dY3xcXpHif 第 23 和 28 行或者在您的示例中,SendCommand()
    • 但该代码在重要方面有所不同(例如,没有指向 SendCommand 的指针)。
    • 这个解决方案对我不起作用,因为我试图访问的结构附加了公共函数(在声明结构的包中声明) - 但是当我尝试要从我的新函数中访问它们,使用上述方法,找不到公共函数。
    【解决方案3】:

    另一种选择是使用类型别名来实现所需的行为。为了可读性,我试图做一些“聪明”的事情:

    type foo struct {
        i int
    }
    
    type foo_ptr = *foo
    
    type foo_ptr_slice = []foo_ptr
    type foo_ptr_map = map[string]foo_ptr
    type foo_ptr_slice_map = map[string]foo_ptr_slice
    
    func (r foo_ptr) dump() {
        fmt.Printf("%d\n", r.i)
    }
    
    func main() {
        // need a map of slice of pointers
        var m foo_ptr_map
    
        m = make(foo_ptr_map, 0)
    
        m["test"] = &foo{i: 1}
    
        var m2 foo_ptr_slice_map
    
        m2 = make(foo_ptr_slice_map, 0)
        m2["test"] = make(foo_ptr_slice, 0, 10)
    
        m2["test"] = append(m2["test"], &foo{i: 2})
    
        fmt.Printf("%d\n", m["test"].i)
        fmt.Printf("%d\n", m2["test"][0].i)
        m["test"].dump()
    }
    

    我承认类型别名用于大规模重构,但为了可读性,这似乎是一个很好的用途。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-18
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 2014-07-30
      相关资源
      最近更新 更多