类型没有字段或方法读取(但它确实)

时间:2015-03-06 21:27:52

标签: go thrift

我很难过这个。在我正在进行的项目中,我们从Thrift生成go代码。代码在包A / B / thriftapi中创建(它曾经是A / B / thrift导致问题,因为所有生成的代码都导入git.apache.org/thrift.git/lib/go/thrift并导致名称冲突)。

我生成了代码并将代码移到了$GOPATH/src/A/B/D然后我尝试构建我的项目并且遇到了大量的错误:

p.X.Read undefined (type Foo has no field or method Read)

我查看了其中一条有问题的行:

import (
    "A/B/D"
    "git.apache.org/thrift.git/lib/go/thrift"
)

func(p *Bar) readField1(iprot thrift.TProtocol) error {
    p.X = D.NewFoo()
    if err := p.X.Read(iprot); err != nil { 
    ...
 }

由于我使用的是IntelliJ,因此我按CTRL +点击了Read()方法,确定它跳转到$GOPATH/A/B/D/ttypes.go方法

func (p *Foo) Read(iprot thrift.TProtocol) error {
    ...
}

这正是我期望该方法所在的文件,它是指向Foo的指针的方法,所以没有问题。一切似乎都应该是正确的,但是在IntelliJ和命令行中我都遇到了这些问题。

任何想法可能会出错?当它告诉我方法不存在时会感到沮丧,但如果我点击它(并且还会在智能感知中弹出),它会让我感到沮丧

编辑 - 每条评论

type Bar struct {
   X Foo `thrift:"x,1,required"`    
}

3 个答案:

答案 0 :(得分:4)

这是你所看到的最小复制品。

package main

type A struct{}

type B *A

func (a *A) Read() {}

func main() {
    var b B
    b.Read()
}

编译会产生以下错误消息:

prog.go:11: b.Read undefined (type B has no field or method Read)

问题在于,节俭正在定义它自己的Foo *D.Foo,这就是b.X的类型。 D.Foo类型在我的代码中由A表示,而thrift引入的Foo类型由B表示。虽然*D.Foo具有Read()方法,但Foo别名却没有。这就是你看到错误信息的原因。在您的情况下,错误消息令人困惑,因为Foo模糊地引用了D.Foo或错误文本中的thrift别名 - 编译器意味着其中之一,并且您将其解释为意味着其他

您可以通过编写(*D.Foo)(b.X).Read()或在复制案例中将值转换为正确的类型来处理别名:

package main

type A struct{}

type B *A

func (a *A) Read() {}

func main() {
    var b B
    (*A)(b).Read()
}

答案 1 :(得分:0)

请不要拒绝投票,但我想表达一个简单的代码来重现您可能遇到的情况。 (我没有使用Thrift的经验,但我认为它与包有更多关系)

package main
import (
    "fmt"
    "D"
)

type Foo struct {}

func (f *Foo) PrintIt() {
    fmt.Println("Sample printing")
}

type Bar struct {
    // For the sake of this experiment
    X *D.Foo
}

func (b *Bar) PrintFromBar() {
    // simulates b.x = D.NewFoo()
    b.X = new(D.Foo) 
    b.X.PrintIt()   // The culprit happens here
}

func main() {
    b := new(Bar)
    b.PrintFromBar()
}

D包:

package D

type Foo struct {}

b.PrintFromBar()以" b.X.PrintIt未定义(类型* D.Foo没有字段或方法PrintIt)失败。

问题可能出在D.NewFoo()Foo创建名为*D.Foo的别名。在你的情况下,由于你的Read()方法已经在D包中,我不知道没有完整的代码。然而,有趣的是,这实际上会产生相同的错误。

答案 2 :(得分:0)

正如@Anyonymous所指出的,这是thrift别名和使用错误的问题。我认为这是Thrift编译器(在0.9.2和当前的HEAD中)中的一个错误,因为它将生成永远不会工作的代码。我们还没有遇到其他语言的问题,只是去吧。以下是重现问题的简化:

// Base.thrift
namespace go a.X.c
struct Foo {
    1: required string s
}

和依赖文件

// Child.thrift
namespace go a.Y.c
include "Base.thrift"

typedef Base.Foo Foo // <---- This is what causes the problem

struct Bar {
    1:Foo f  // <-- Will error
    // 1:Base.Foo f   Need to comment out typedef and use this instead
}

按原样编译thrift会没问题,但是当你去安装a.Y.c包时会产生:

/scratch/go/src/a/Y/c/ttypes.go:78: cannot use c.Foo literal (type *c.Foo) as type *Foo in assignment
/scratch/go/src/a/Y/c/ttypes.go:79: p.F.Read undefined (type *Foo has no field or method Read)
/scratch/go/src/a/Y/c/ttypes.go:105: p.F.Write undefined (type *Foo has no field or method Write)

如果我注释掉typedef并交换Bar中的行,那么一切正常。这似乎只发生在Go。