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

Fur*_*rge 7 thrift go

我很难过这个.在我正在进行的项目中,我们从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)
Run Code Online (Sandbox Code Playgroud)

我看了一条令人讨厌的台词:

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 { 
    ...
 }
Run Code Online (Sandbox Code Playgroud)

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

func (p *Foo) Read(iprot thrift.TProtocol) error {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

编辑 - 每条评论

type Bar struct {
   X Foo `thrift:"x,1,required"`    
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*kin 5

这是您所看到内容的最小复制。

package main

type A struct{}

type B *A

func (a *A) Read() {}

func main() {
    var b B
    b.Read()
}
Run Code Online (Sandbox Code Playgroud)

编译产生此错误信息:

prog.go:11: b.Read undefined (type B has no field or method Read)
Run Code Online (Sandbox Code Playgroud)

问题在于,节俭正在定义它的本身Foo,这就是*D.Foo的类型b.X。的D.Foo类型被表示为A在我的代码,和Foo类型的节俭介绍由下式表示B。尽管*D.FooRead()方法,但Foo别名没有。这就是为什么您看到错误消息的原因。错误消息在您的情况下令人困惑,因为在错误文本中Foo含糊不清地引用D.Foo或节俭别名–编译器表示其中一个,而您将其解释为另一个。

您可以通过写(*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()
}
Run Code Online (Sandbox Code Playgroud)


Fur*_*rge 1

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

// Base.thrift
namespace go a.X.c
struct Foo {
    1: required string s
}
Run Code Online (Sandbox Code Playgroud)

和依赖文件

// 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
}
Run Code Online (Sandbox Code Playgroud)

按原样编译 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)
Run Code Online (Sandbox Code Playgroud)

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