This:
[]Bar(foos)
是一种类型转换。根据规范,转换有特定的规则:
非常数值x
可以转换为类型T
在任何这些情况下:
-
x
is 可分配的 to T
.
-
x
的类型和T
具有相同的基础类型。
-
x
的类型和T
是未命名的指针类型,并且它们的指针基类型具有相同的基础类型。
-
x
的类型和T
都是整数或浮点类型。
-
x
的类型和T
都是复杂类型。
-
x
是一个整数或字节或符文的切片并且T
是字符串类型。
-
x
是一个字符串并且T
是字节或符文的切片。
此处均不适用。为什么?
因为底层类型[]Foo
与底层类型不同[]Bar
.和类型的值[]Foo
不可分配给类型的变量[]Bar
, see 可分配性规则在这里.
底层类型为Foo
与底层类型相同Bar
,但这同样不适用于元素类型为的切片Foo
and Bar
.
所以以下工作:
type Foo struct{ A int }
type Foos []Foo
type Bars Foos
func main() {
foos := []Foo{Foo{1}, Foo{2}}
bars := Bars(foos)
fmt.Println(bars)
}
输出(尝试一下去游乐场):
[{1} {2}]
请注意,由于实际的内存表示Foo
and Bar
是相同的(因为底层类型Bar
is Foo
),在这种情况下使用包unsafe您可以“查看”的值[]Foo
作为一个值[]Bar
:
type Foo struct{ A int }
type Bar Foo
func main() {
foos := []Foo{Foo{1}, Foo{2}}
bars := *(*[]Bar)(unsafe.Pointer(&foos))
fmt.Println(bars)
fmt.Printf("%T", bars)
}
This: *(*[]Bar)(unsafe.Pointer(&foos))
意味着取地址foos
,将其转换为unsafe.Pointer (根据规格所有指针都可以转换为unsafe.Pointer
),那么这个Pointer
被转换为*[]Bar
(再次根据规范Pointer
可以转换为任何其他指针类型),然后该指针被取消引用(*
运算符),因此结果是类型的值[]Bar
如输出中所示。
输出(尝试一下去游乐场):
[{1} {2}]
[]main.Bar
Notes:
引用包文档unsafe
:
unsafe 包包含绕过 Go 程序类型安全的操作。
导入不安全的包可能是不可移植的,并且不受 Go 1 兼容性指南的保护。
这是什么意思?这意味着您不应该恢复使用包usafe
每次它都会让你的生活变得更轻松。你应该只在特殊情况下使用它,如果不使用它会使你的程序变得非常缓慢和复杂。
在您的程序中,情况并非如此,因为我提出了一个仅进行一点重构的工作示例(Foos
and Bars
是切片)。
unsafe
围绕 Go 类型安全的步骤。这是什么意思?如果你想改变类型foos
(例如非常像foos := "trap!"
),您的程序仍会编译并运行,但很可能会发生运行时恐慌。使用usafe
你会失去编译器的类型检查。
而如果你使用我的其他建议(Foos
and Bars
),此类更改/拼写错误会在编译时检测到。