【问题标题】:School me on Go packages, imports and protos教我 Go 包、导入和原型
【发布时间】:2020-10-04 14:58:40
【问题描述】:

我最熟悉 Python 和 bazel 构建环境。我正在尝试在 Go 中重写一部分代码,并且我正在努力让 proto 导入正确对齐。

github.com/djhedges/exit_speed/gps.proto 我已经设置了 go_package 像这样

option go_package = "github.com/djhedges/exit_speed/gps_go_proto";

我添加了一个反射器.proto,它导入 gps.proto 并重用其中定义的一些消息。

import "gps.proto";

我用

编译gps.proto
protoc -I ./ --go_out=./ --go_opt=paths=source_relative --python_out ./ gps.proto

并编译reflector.proto

LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1 python3 -m grpc_tools.protoc -I ./ --go_out=./ --go_opt=paths=source_relative --python_out ./ --grpc_python_out ./ reflector.proto

最后在 exit_speed/reflector.go 我尝试导入 gps_go_proto

import gpspb "github.com/djhedges/exit_speed/gps_go_proto"

哪些错误

go: finding github.com/djhedges/exit_speed/gps_go_proto latest
reflector.go:21:2: unknown import path "github.com/djhedges/exit_speed/gps_go_proto": cannot find module providing package github.com/djhedges/exit_speed/gps_go_proto

如果可能,我更愿意将 gps.proto 保留在根目录中,因为我已将 protos 登录到数据文件中,并且我相信移动它会破坏 proto 解析。我想我可以写一个迁移脚本。

我也对如何使用不同的 go 包和导入设置多个原型感到困惑。 go 包必须有一个专用文件夹吗?

【问题讨论】:

    标签: go protocol-buffers


    【解决方案1】:

    如果我对 go 包的理解正确,包名必须映射到一个目录。通过将--go_out=./ 更改为--go_out=./gps_go_proto 似乎可以解决我的问题,而无需移动原始文件。这确实意味着我有一些额外的目录,但这似乎还可以。

    【讨论】:

      【解决方案2】:

      正如Go Specification import section 所说:

      进口声明

      导入声明声明包含该声明的源文件取决于导入包 (§Program initialization and execution) 的功能,并允许访问该包的 exported 标识符。导入命名用于访问的标识符 (PackageName) 和指定要导入的包的 ImportPath。

      ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
      ImportSpec       = [ "." | PackageName ] ImportPath .
      ImportPath       = string_lit .
      

      (在此处截取,我破坏了一些链接;使用第一个链接获取带有链接的文本)。字符串文字很熟悉:

      import "github.com/..."
      

      部分; PackageName 或一个点是可选的。回到正文:

      ImportPath 的解释取决于实现,但它通常是已编译包的完整文件名的子字符串,并且可能与已安装包的存储库相关。

      在您自己的答案中,您添加:

      如果我正确理解 go 包,则包名必须映射到目录。

      这不是必然。由实现决定字符串文字的含义。不过,一般来说,Go 构建系统会使用此路径找到一个充满文件的目录。它还可以使用版本控制系统,例如 Git,来填充一个充满文件的目录,以便编译器可以找到它们。

      我发现有点令人惊讶,但最后,完全有意义( 在规范中描述)是这样的:在package clause 中找到的包名称:

      package somename
      

      某些导入文件顶部的语句有时是不相关的。当然,一个充满了实现包 x 的文件的目录会让它们都说package x。但它是该行中的y 标识符:

      import y "path/to/x"
      

      您的 包中,该包提供您用于访问导出标识符的名称。您在此处使用的名称(导入以 y 作为包名称)是 y,即使包本身显示为 package x。包x 中的包子句实际上只是推荐名称x,因此您可以这样写:

      import "path/to/x"
      

      如果您想将这些称为x.Thing

      字符串文字也不需要提及x:也许所有文件都在通过path/to/z找到的东西中,你写:

      import "path/to/z"
      

      然后(仍然)写x.Thing,因为path/to/z/*.go 中的文件推荐x 作为包名。

      protoc 如何使用它

      不管上述情况如何,protobuf Go 生成器都会在生成的 name*.pb.go* Go 代码中打印一个 import 指令。 import 指令将显示为:

      import "some/path/here"
      

      您可以使用option go_package 指定字符串文字。 protobuf 编译器需要自行解释。但是,作为the documentation notes,这些<em>name</em>.pb.go 文件本身将被放入某个目录中。当然,它们还将包含 package <em>pkg</em> 行。

      • 每个输出文件的位置取决于您是否使用--go_opt=paths=source_relative。如果你这样做了,go_package 选项字符串在这里变得无关紧要。

      • .pb.go 文件生成器采用go_package 选项字符串,去掉包括最后一个斜杠在内的所有内容,并将剩余的字符串用于package 行。

      点意味着不管 Go 系统本身做什么,它如何找到这些文件,以及你如何编写自己的imports,推荐包名 in 这些文件将是 go_package 选项中的最后一个组件。所以从某种意义上说,你真正需要的只是最终组件。但是如果你的 Go 实现需要更多,你可以提供更多。

      第一个点表示如果你使用--go_opt=paths=source_relativego_package选项中的文本其余重要的是:Go 生成器将尝试使用该字符串来生成输出文件。因此,如果您的 Go 实现需要更多,并且您确实提供了更多,并且它与您想要的输出文件名不匹配,那么您肯定需要 --go-opt

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        • 2021-07-26
        • 2019-12-06
        • 2013-08-17
        • 1970-01-01
        • 2016-05-30
        • 2016-07-24
        相关资源
        最近更新 更多