【问题标题】:How to implement interfaces in following code?如何在以下代码中实现接口?
【发布时间】:2016-06-29 07:35:29
【问题描述】:

我有以下代码,我想使用接口:

当前代码:

import (        
    "github.com/dorzheh/deployer/ui/dialog_ui"
    . "github.com/dorzheh/go-dialog"
)

// all methods in https://github.com/dorzheh/deployer/blob/master/ui/dialog_ui/dialog_ui.go#L28
type Pb struct {
    sleep time.Duration
    step  int
}

type DialogUi struct {
    *Dialog //The source is https://github.com/dorzheh/go-dialog/blob/master/dialog.go#L34
    Pb *Pb
}

我正在尝试以这种方式实现接口:

import (
    "testing"
    // . "github.com/dorzheh/go-dialog"
    //"github.com/dorzheh/deployer/ui/dialog_ui"
)


type PBifaceT interface {
    Step() int
}

type TestDialogUiT struct {
    Pb *PBifaceT
}

func TestUiValidateUser(t *testing.T) {
    x := dialog_ui.TestDialogUiT{}
    PbPb := ImplPBifaceT{}
    x.Pb = PbPb

    parentId := x.Pb.Step()
    t.Logf(fmt.Sprintf("%v", parentId))
}

我创建了一个playground。如您所见,它在以下错误中运行:

prog.go:23: cannot use PbPb (type ImplPBifaceT) as type *PBifaceT in assignment:
    *PBifaceT is pointer to interface, not interface
prog.go:25: x.Pb.Step undefined (type *PBifaceT is pointer to interface, not interface)

我尝试将它们转换为in this playground

func NewD() *PBifaceT {
    // var err error
    var res =new(ImplPBifaceT)
    return (*PBifaceT)(res)
}

func main() {
    x := TestDialogUiT{}
    x.Pb = NewD()
    parentId := x.Pb.Step()
    fmt.Sprintf("%v", parentId)

}

问题:

prog.go:23: cannot convert res (type *ImplPBifaceT) to type *PBifaceT
prog.go:30: x.Pb.Step undefined (type *PBifaceT is pointer to interface, not interface)

【问题讨论】:

    标签: pointers go interface


    【解决方案1】:

    您确定需要 Pb 字段作为 *PBifaceT

    如果你把它作为一个

    type TestDialogUiT struct {
        Pb *PBifaceT
    }
    

    你会的

    x := TestDialogUiT{}
    
    PbPb := ImplPBifaceT{}
    x.Pb = PBifaceT(PbPb)
    
    parentId := x.Pb.Step()
    fmt.Printf("%v", parentId)
    

    它工作正常..

    看看这个playground,看看它是否有帮助。

    我建议你看看这个tutorialthis doc

    我建议您也阅读this SO answer,它解释了您不应该如何使用接口指针

    背景:在 Go 中,由于两个原因,您传递指向某事物的指针:

    1)你想要,因为你的结构真的很大,你想避免复制

    2)您需要这样做,因为 calee 想要修改原始文件(这对于带有指针接收器的方法来说很典型)。现在接口值非常小(只有两个字),因此不适用将指针传递给接口值的原因 1。

    原因 2 在大多数情况下并不适用,因为将指针传递给接口值将允许您更改接口值本身,但大多数情况下您希望修改存储在接口值中的值。存储在接口值中的这个值通常是一个指针值,它允许通过调用接口值上的方法来更改结构的值,该接口值包装了指向该结构的指针。这听起来很复杂,但实际上并不复杂:新手 Go 程序员只是不使用指向接口的指针(因为这不会有任何好处),而有经验的 Go 程序员不使用指向接口的指针(因为它不会做太多好)除非他需要修改接口值,通常是在反射期间。

    【讨论】:

    • @ValeriySolovyov 为什么你真的需要有一个接口指针?
    【解决方案2】:

    您可以通过链接使用 Pb,您只是在分配时缺少指针引用。

    package main
    
    import (
        "fmt"
    )
    
    type PBifaceT interface {
        Step() int
    }
    
    type TestDialogUiT struct {
        Pb PBifaceT
    }
    type ImplPBifaceT struct {
    }
    
    func (m *ImplPBifaceT) Step() int {
        return 0
    }
    
    func main() {
        x := TestDialogUiT{}
        PbPb := &ImplPBifaceT{}
        x.Pb = PbPb
    
        parentId := x.Pb.Step()
        fmt.Printf("%v", parentId)
    }
    

    请参考这个游乐场链接:https://play.golang.org/p/N7quQFpYU0 更改发生在第 12、17、23 和 27 行。

    【讨论】:

      【解决方案3】:

      不要使用指向接口的指针,除非您确定这是您想要的,请参阅TestDialogUiT 中的Pb *PBifaceT。如果您将其更改为 Pb PBifaceT,您的游乐场链接就可以正常工作。

      接口已经是一个指针。

      【讨论】:

      • 所以我改成了play.golang.org/p/syEqU159Ut,它的工作。我应该如何使用此代码来实现与当前代码相同的结果但使用接口?
      • 我需要通过链接(指针)使用 Pb 而不是值 play.golang.org/p/dLMK5WKBa3
      • 您的 NewD 可以只是 return res 在大多数情况下,Go 将为您处理指针取消引用。您只需要关心如何创建ImplPBifaceT,因为它可以是一个值或一个指针。在大多数情况下,指针就可以了,并且会按照您的预期工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-02
      • 1970-01-01
      相关资源
      最近更新 更多