类型没有字段或方法读取(但有)
I'm stumped on this one. In the project that I'm working on, we generate go code from Thrift. The code gets created in the package A/B/thriftapi (which used to be A/B/thrift which was causing problems because all of the generated code was importing git.apache.org/thrift.git/lib/go/thrift
and causing name collisions).
I generated the code and moved the code into $GOPATH/src/A/B/D
I then tried to build my project and was getting tons of errors of the form:
p.X.Read undefined (type Foo has no field or method Read)
I looked at one of the offending lines:
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 {
...
}
Since I am using IntelliJ, I CTRL+clicked on the Read()
method and sure enough it jumps to $GOPATH/A/B/D/ttypes.go
to the method
func (p *Foo) Read(iprot thrift.TProtocol) error {
...
}
That's exactly the file I'd expect the method to be in, and it's a method on a pointer to Foo
so no problems there. Everything seems like it should be right, but both in IntelliJ and on the command line I get these problems.
Any ideas what might be going wrong? It's frustrating when it tells me the method doesn't exist, yet will take me right to it if I click on it (and also pops up in the intellisense)
EDIT - Per comment
type Bar struct {
X Foo `thrift:"x,1,required"`
}
我很困惑。 在我正在从事的项目中,我们从Thrift生成go代码。 该代码是在A / B / thriftapi包(以前是A / B / thrift)中创建的,因为所有生成的代码都在导入 我生成了代码,并将代码移到了 在有问题的一行之一: p>
由于我使用的是IntelliJ,因此我按住CTRL键并单击了 这正是我希望该方法所在的文件,并且 这是指向 任何想法可能出了什么问题? 告诉我该方法不存在,这很令人沮丧,但是如果我单击该方法(它还会在智能感知中弹出),它将带我直接使用它 p>
编辑-每个注释
git.apache.org/thrift.git/lib/go,这导致了问题 / thrift code>并导致名称冲突)。 p>
$ GOPATH / src / A / B / D code>中,然后我尝试构建我的项目,并收到大量错误 格式: p>
pXRead未定义(类型Foo没有字段或方法Read)
code> pre>
import(
“ A / B / D”
“ git.apache.org/thrift.git/lib/go/thrift “
)
func(p * Bar)readField1(iprot thrift.TProtocol)错误{
pX = D.NewFoo()
如果err:= pXRead(iprot); err!= nil {
...
}
code> pre>
Read() code>方法,并且肯定会跳转到
$ GOPATH / A / B / D / ttypes.go code>到方法 p>
func(p * Foo )读取(iprot thrift.TProtocol)错误{
...
}
code> pre>
Foo code>的指针的方法,因此那里没有问题。 一切似乎都应该正确,但是在IntelliJ和命令行中,我都遇到了这些问题。 p>
type条形结构{
X Foo`thrift:“ x,1,required”`
}
code> pre>
div >
As @Anyonymous points out, this is a problem with thrift aliasing and using the wrong one. I consider this a bug in the Thrift compiler (in 0.9.2 and current HEAD) in that it will generate code that will never work. We haven't run into this problem with other languages, just go. Here is a simplification to reproduce the problem:
// Base.thrift
namespace go a.X.c
struct Foo {
1: required string s
}
and the depenant file
// 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
}
Compiling the thrift as is will be fine, but when you go to install the a.Y.c
package will produce:
/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)
If I comment out the typedef and swap the lines in Bar
then everything works fine. This appears to only happen in Go.
Please do not vote down, but I want to express a simple code to reproduce what you might have encountered. (I have no experience with Thrift, but I think it has more to do with packages)
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()
}
The D package:
package D
type Foo struct {}
b.PrintFromBar()
fails with "b.X.PrintIt undefined (type *D.Foo has no field or method PrintIt).
The problem might lies in D.NewFoo()
creating an alias named Foo
for *D.Foo
. In your case since your Read()
method is already inside the D package, I have no idea without the full code. However, it's interesting that this actually produce the same error.
Here's a minimal reproduction of what you're seeing.
package main
type A struct{}
type B *A
func (a *A) Read() {}
func main() {
var b B
b.Read()
}
Compiling produces this error message:
prog.go:11: b.Read undefined (type B has no field or method Read)
The problem is that thrift is defining it's own Foo
which is *D.Foo
, and that's the type of b.X
. The D.Foo
type is represented by A
in my code, and the Foo
type that thrift introduces is represented by B
. Although *D.Foo
has a Read()
method, the Foo
alias doesn't. That's why you're seeing the error message. The error message is confusing in your case because Foo
is ambiguously referring to D.Foo
or the thrift alias in the text of the error — the compiler means one of them, and you're interpreting it to mean the other.
You can work through the alias by converting the value to the right type by writing (*D.Foo)(b.X).Read()
or in the reproduction case:
package main
type A struct{}
type B *A
func (a *A) Read() {}
func main() {
var b B
(*A)(b).Read()
}