Fré*_*els 5 type-conversion go slice
我是Go的新手,所以这可能是显而易见的.编译器不允许以下代码:(http://play.golang.org/p/3sTLguUG3l)
package main
import "fmt"
type Card string
type Hand []Card
func NewHand(cards []Card) Hand {
hand := Hand(cards)
return hand
}
func main() {
value := []string{"a", "b", "c"}
firstHand := NewHand(value)
fmt.Println(firstHand)
}
Run Code Online (Sandbox Code Playgroud)
错误是:
/tmp/sandbox089372356/main.go:15: cannot use value (type []string) as type []Card in argument to NewHand
从规范来看,它看起来像[]字符串与[]卡的底层类型不同,因此不能进行类型转换.
确实是这样,还是我错过了什么?
如果是这样的话,为什么会这样呢?假设,在一个非宠物示例程序中,我输入一个字符串片段,有没有办法将它"转换"成一片卡片,或者我是否必须创建一个新结构并将数据复制到其中?(我想避免使用,因为我需要调用的函数将修改切片内容).
底层类型Card
可能与底层类型string
(它本身string
:) []Card
相同,但底层类型与底层类型不同[]string
(因此同样适用Hand
).
你不能切片转换T1
到一片T2
,这不是他们有什么基础类型的问题,如果T1
是不相同的T2
,你就不能.为什么?因为不同元素类型的切片可能具有不同的内存布局(内存中的大小不同).例如,类型的元素[]byte
每个占用1个字节.每个元素[]int32
占用4个字节.显然,即使所有值都在范围内,您也不能将其中一个转换为另一个0..255
.
但回到根源:如果你需要一片Card
s,你为什么要在一开始创建一片string
s?您所创建的类型 Card
,因为它不是一个string
(或至少不只是一个string
).如果是这样且您需要[]Card
,那么[]Card
首先创建并解决所有问题:
value := []Card{"a", "b", "c"}
firstHand := NewHand(value)
fmt.Println(firstHand)
Run Code Online (Sandbox Code Playgroud)
请注意,您仍然可以Card
使用无类型常量string
文字初始化切片,因为它可用于初始化其基础类型为的任何类型string
.如果要涉及类型string
常量或类型的非常量表达式string
,则需要显式转换,如下例所示:
s := "ddd"
value := []Card{"a", "b", "c", Card(s)}
Run Code Online (Sandbox Code Playgroud)
如果你有[]string
,你需要手动建立一个[]Card
.没有"更容易"的方式.您可以创建辅助toCards()
函数,以便在需要的任何地方使用它.
func toCards(s []string) []Card {
c := make([]Card, len(s))
for i, v := range s {
c[i] = Card(v)
}
return c
}
Run Code Online (Sandbox Code Playgroud)
一些背景和推理链接:
为什么[]字符串无法在golang中转换为[] interface {}
出于技术上的原因,禁止在元素具有相同基础类型(例如[]string
和[]Card
)的切片之间进行转换。这是一项规范决策,旨在避免偶然的具有相同结构的不相关类型之间的意外转换。
安全的解决方案是复制切片。但是,可以使用不安全的软件包直接进行转换(不进行复制):
value := []string{"a", "b", "c"}
// convert &value (type *[]string) to *[]Card via unsafe.Pointer, then deref
cards := *(*[]Card)(unsafe.Pointer(&value))
firstHand := NewHand(cards)
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/tto57DERjYa
软件包文档中的强制性警告:
unsafe.Pointer
允许程序击败类型系统并读写任意内存。使用时应格外小心。
在2011 年的邮件列表中,对转换和基础类型进行了讨论,并在2016年提出了允许在递归等效类型之间进行转换的提议,但该提议被拒绝,直到有更令人信服的理由为止。