Golang结构类型转换

发布于 2025-02-09 08:14:46 字数 983 浏览 2 评论 0原文

我试图弄清楚GO处理结构之间的类型转换。我读过的所有内容都告诉我,具有相同基础类型的类型被认为是兼容的,类型转换隐含地发生。如果是这样,为什么下面的代码不起作用? foobar实现fooi接口,它们都添加了类型字符串的x属性。但是,当我将类型bar的结构传递给AcceptBarorfoo,该期望类型foo 的结构时,我会得到类型的不匹配编译错误。

Go Playground

package main

import (
    "play.ground/bar"
    "play.ground/foo"
)

func main() {
    AcceptBarOrFoo(bar.Bar{})
}

func AcceptBarOrFoo(foo.Foo) interface{} {
    return nil
}

// -- iface/iface.go --

package iface

type FooI interface {
    a() string
    b(int) int
}
// -- foo/foo.go --
package foo

import (
    "play.ground/iface"
)

type Foo struct {
    iface.FooI
    x string
}
// -- bar/bar.go --
package bar

import (
    "play.ground/iface"
)

type Bar struct {
    iface.FooI
    x string
}

I'm trying to figure out how go handles type conversion between structs. Everything I have read tells me that types with the same underlying type are considered compatible and type conversion happens implicitly. If that is the case, why does the code below not work? Both Foo and Bar implement the FooI interface, and they both add an x property of type string. Yet, when I pass a struct of type Bar to AcceptBarOrFoo that expects a struct of type Foo, I get a type mismatch compile error.

Go Playground

package main

import (
    "play.ground/bar"
    "play.ground/foo"
)

func main() {
    AcceptBarOrFoo(bar.Bar{})
}

func AcceptBarOrFoo(foo.Foo) interface{} {
    return nil
}

// -- iface/iface.go --

package iface

type FooI interface {
    a() string
    b(int) int
}
// -- foo/foo.go --
package foo

import (
    "play.ground/iface"
)

type Foo struct {
    iface.FooI
    x string
}
// -- bar/bar.go --
package bar

import (
    "play.ground/iface"
)

type Bar struct {
    iface.FooI
    x string
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中楼上月下 2025-02-16 08:14:46

FOO的X与Bar的X不同,因为在软件包边界之间,非出口标识符永远不会相等。修复导出 foo.foo.foo.foo.foo和bar.bar.bar.bar.bar.bar:

type Foo struct {
    iface.FooI
    X string // <-- start with capital letter to export
}

使用foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo.foo或bar.bar作为参数值,foo.foo和bar.bar必须为可分配的参数类型。使用foo.foo作为参数类型是不起作用的,因为命名类型无法彼此分配。但是,当两种类型共享相同的基础类型时,命名类型可分配给未命名类型。将参数声明为未命名类型:

func AcceptBarOrFoo(struct {
    iface.FooI
    X string
}) interface{} {
    return nil
}

使用这些更改,以下代码编译:

AcceptBarOrFoo(bar.Bar{})
AcceptBarOrFoo(foo.Foo{})

在去操场

另一个选项是使用转换在以下代码中,foo.foo是通用类型,bar.bar被转换为foo.foo。

func Accept(foo.Foo) interface{} {
    return nil
}

... 

Accept(foo.Foo{})
Accept(foo.Foo(bar.Bar{}))

在Go Playground上运行示例

注意:foo.foo和bar.bar必须具有上述工作的相同字段(字段名称已导出,以相同顺序为字段,字段,字段具有相同的类型)。


关于GO的一些注释:

  • 转换从一种具体类型到另一种混凝土类型。
  • GO以表达式没有隐式转换而闻名,但是在某些

Foo's x is different from Bar's x because non-exported identifiers are never equal across package boundaries. Fix by exporting the fields in foo.Foo and bar.Bar:

type Foo struct {
    iface.FooI
    X string // <-- start with capital letter to export
}

To use a foo.Foo or bar.Bar as an argument value, a foo.Foo and bar.Bar must be assignable to the argument's type. It does not work to use foo.Foo as the argument type because named types are not assignable to each other. However, named types are assignable to unnamed types when the two types share the same underlying type. Declare the argument as an unnamed type:

func AcceptBarOrFoo(struct {
    iface.FooI
    X string
}) interface{} {
    return nil
}

With these changes, the following code compiles:

AcceptBarOrFoo(bar.Bar{})
AcceptBarOrFoo(foo.Foo{})

Run the example on the Go playground

Another option is to use a conversion to a common type. In the following code, foo.Foo is the common type and bar.Bar is converted to a foo.Foo.

func Accept(foo.Foo) interface{} {
    return nil
}

... 

Accept(foo.Foo{})
Accept(foo.Foo(bar.Bar{}))

Run the example on the Go playground.

Note: foo.Foo and bar.Bar must have the same fields for the above to work (field names are exported, fields in same order, fields have same types).


Some notes about Go:

  • There are conversions from one concrete type to another.
  • Go is famous for having no implicit conversions in expressions, but there are implicit conversions in some assignment scenarios.
來不及說愛妳 2025-02-16 08:14:46

您不能将一种混凝土类型转换为另一种混凝土类型。他们不一样。无法在GO中定义这种自动铸造。充其量,您可以定义一个接受bar的函数,并构建和返回新的foo,其字段设置为与输入bar 。

我所读过的所有内容都告诉我,如果基础类型相同,高阶类型被认为是兼容的,类型转换可能会隐含地发生

那么您的来源是什么,但是 nothing 暗示了这一点,这根本不是真的。 Go做 no 隐含的转换,对任何事物。这是GO的大型,大声宣传的功能。给定类型foo struct {a int}type bar struct {a int},您永远无法将类型bar的对象分配给变量类型foo

当该类型满足接口时,您 can can 从任何一个具体类型转换为接口类型。您的AcceptBarorfoo方法应接受接口类型(foobar满意),而不是混凝土类型。鉴于接口仅定义方法(不是成员),并且给定foobar具有任何方法,您的接口将是空接口,接口>接口{} < /代码>。传递的值将无目的,除非您以后将其转换回混凝土类型以访问其成员,但这并不是接口的目的。

You cannot convert one concrete type to another concrete type, ever. They are not the same. There is no way to define this type of automatic casting in Go. At best, you could define a function that accepts a Bar and builds and returns a new Foo with its fields set to the same values as the input Bar.

Everything I have read tells me that if the underlying types are the same, the higher order types are considered compatible and type conversion happens implicitly

It's unclear what your source for this is, but nothing would have ever stated or implied this, it's simply not true. Go does no implicit conversion, of anything. That's a big, loudly advertised feature of Go. Given type Foo struct { a int } and type Bar struct { a int }, you can never assign an object of type Bar to a variable of type Foo.

You can convert from either concrete type to an interface type, when the type satisfies the interface. Your AcceptBarOrFoo method should accept an interface type (which both Foo and Bar satisfy), not a concrete type. Given that interfaces only define methods (not members), and given neither Foo or Bar have any methods, your interface would be the empty interface, interface{}. The value passed in would serve no purpose, except for you to later convert it back to a concrete type to access its members, but that's not really what interfaces are for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文