在VSCode中使用Go项目时,我注意到gopls报告了一个问题,这个问题对于编译器来说是正常的。
我提取了一个最小示例如下:
假设我们有一个项目,包含包foo
(文件foo.go
)和bar
(文件bar.go
)。
包foo
导出类型约束A
:
// foo.go
package foo
type A comparable
包bar
消耗约束A
作为
// bar.go
package bar
// import "foo"
func F[T foo.A](a T, b T) bool {
return a == b
}
由于约束A
"继承"自comparable
,表达式a == b
是明确定义的:T
被约束于A
,后者是可以比较的,因此==
可用于类型为T
的值。编译器对代码满意。
但是VSCode报告a == b
作为问题:
无效操作:a == b(在类型集中不可比较的类型)
在编辑器中,
两个观察:
- 如果约束
type A comparable
在包bar
中定义,那么对于gopls来说是没问题的——这是一个跨包问题 - 如果约束被定义为
type A = comparable
(即在包foo
中定义为typedef,而不是"newtype"),那么也是没问题的
8条答案
按热度按时间ztigrdn81#
根据描述,我怀疑是导出/导入的问题。
确认了。如果我关闭导出数据,问题就消失了。
6vl6ewon2#
问题在于命名类型转发破坏了内置的
comparable
和A
之间的关系。也就是说:生成的类型A
的底层是一个空接口,隐藏的comparable
位被设置。请注意,
type A interface{comparable}
实际上是相同的类型,但没有这个问题,因为可比位被编码为显式嵌入的可比类型。修复这个问题有点棘手,因为在
go/types
API中无法直接访问或设置可比位。我们唯一能做的就是通过检查A.Underlying()
和types.Universe.Lookup("comparable").Underlying()
之间的指针相等来识别这个特定情况。虽然感觉有点脏,但应该有效。这需要仔细审查,所以不会发布 v0.13.0 版本。转到 v0.13.1。
s8vozzvw3#
另外想说:感谢你仔细的发布报告!这使得追踪这个问题变得更容易。
s5a0g9ez4#
感谢您提供的解决方法
type A interface{comparable}
-它对我有效:)o7jaxewo5#
感谢您提供的解决方法
type A interface{comparable}
-它对我有效:)qvsjd97n6#
由于这种情况相对较不可能发生,并且有一个简单的解决方法,因此将问题抛给gopls@v0.14.0。
8yparm6h7#
我猜这是go/types的问题。
这个问题在使用go1.21rc3构建的gopls和v0.13.0-pre.2版本的gopls时是可重现的。
cc @findleyr@griesemer@adonovan
omtl5h9j8#
根据描述,我怀疑是关于导出/导入的问题。我会紧急查看并解决这个问题。对于v0.13.0版本来说,修复这个问题会很好。