dsfsfdsf4544
2015-03-13 11:42
浏览 227
已采纳

将字符串切片转换为自定义类型的切片

I'm quite new to Go, so this might be obvious. The compiler does not allow the following code: (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)
}

The error is: /tmp/sandbox089372356/main.go:15: cannot use value (type []string) as type []Card in argument to NewHand

From the specs, it looks like []string is not the same underlying type as []Card, so the type conversion cannot occur.

Is it, indeed, the case, or did I miss something?

If it is the case, why is it so? Assuming, in a non-pet-example program, I have as input a slice of string, is there any way to "cast" it into a slice of Card, or do I have to create a new structure and copy the data into it? (Which I'd like to avoid since the functions I'll need to call will modify the slice content).

图片转代码服务由CSDN问答提供 功能建议

我刚开始使用Go,所以这很明显。 编译器不允许以下代码: ( http://play.golang.org/p/3sTLguUG3l

 包main 
 
import“ fmt” 
 
type卡字符串
type Hand [] Card 
 
func NewHand(cards [] Card  )手{
手:=手(牌)
返回手
} 
 
func main(){
值:= []字符串{“ a”,“ b”,“ c”} 
  firstHand:= NewHand(值)
 fmt.Println(firstHand)
} 
   
 
 

错误是: / tmp / sandbox089372356 / main .go:15:不能将值(类型[] string)用作类型[] Card到NewHand的参数中

从规格来看,看起来[] string不是 与[] Card相同的基础类型,因此无法进行类型转换。

是这样,还是我错过了什么?

如果是这样,为什么会这样? 假设在一个非宠物示例程序中,我输入了一个字符串切片,是否可以将其“投射”到Card切片中,或者是否必须创建一个新结构并将数据复制到其中 ? (这是我想避免的,因为我需要调用的函数会修改切片内容)。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • douguaidian8021 2015-03-13 13:00
    已采纳

    The underlying type of Card might be the same as the underlying type of string (which is itself: string), but the underlying type of []Card is not the same as the underlying type of []string (and therefore the same applies to Hand).

    You cannot convert a slice of T1 to a slice of T2, it's not a matter of what underlying types they have, if T1 is not identical to T2, you just can't. Why? Because slices of different element types may have different memory layout (different size in memory). For example the elements of type []byte occupy 1 byte each. The elements of []int32 occupy 4 bytes each. Obviously you can't just convert one to the other even if all values are in the range 0..255.

    But back to the roots: if you need a slice of Cards, why do you create a slice of strings in the first place? You created the type Card because it is not a string (or at least not just a string). If so and you require []Card, then create []Card in the first place and all your problems go away:

    value := []Card{"a", "b", "c"}
    firstHand := NewHand(value)
    fmt.Println(firstHand)
    

    Note that you are still able to initialize the slice of Card with untyped constant string literals because it can be used to initialize any type whose underlying type is string. If you want to involve typed string constants or non-constant expressions of type string, you need explicit conversion, like in the example below:

    s := "ddd"
    value := []Card{"a", "b", "c", Card(s)}
    

    If you have a []string, you need to manually build a []Card from it. There is no "easier" way. You can create a helper toCards() function so you can use it everywhere you need it.

    func toCards(s []string) []Card {
        c := make([]Card, len(s))
        for i, v := range s {
            c[i] = Card(v)
        }
        return c
    }
    

    Some links for background and reasoning:

    Go Language Specification: Conversions

    why []string can not be converted to []interface{} in golang

    Cannot convert []string to []interface {}

    What about memory layout means that []T cannot be converted to []interface in Go?

    点赞 打赏 评论
  • dssqq82402 2015-03-13 11:47

    From the specs, it looks like []string is not the same underlying type as []Card, so the type conversion cannot occur.

    Exactly right. You have to convert it by looping and copying over each element, converting the type from string to Card on the way.

    If it is the case, why is it so? Assuming, in a non-pet-example program, I have as input a slice of string, is there any way to "cast" it into a slice of Card, or do I have to create a new structure and copy the data into it? (Which I'd like to avoid since the functions I'll need to call will modify the slice content).

    Because conversions are always explicit and the designers felt that when a conversion implicitly involves a copy it should be made explicit as well.

    点赞 打赏 评论
  • dongya8378 2018-02-01 01:44

    There is no technical reason why conversion between slices whose elements have identical underlying types (such as []string and []Card) is forbidden. It was a specification decision to help avoid accidental conversions between unrelated types that by chance have the same structure.

    The safe solution is to copy the slice. However, it is possible to convert directly (without copying) using the unsafe package:

    value := []string{"a", "b", "c"}
    // convert &value (type *[]string) to *[]Card via unsafe.Pointer, then deref
    cards := *(*[]Card)(unsafe.Pointer(&value))
    firstHand := NewHand(cards)
    

    https://play.golang.org/p/tto57DERjYa

    Obligatory warning from the package documentation:

    unsafe.Pointer allows a program to defeat the type system and read and write arbitrary memory. It should be used with extreme care.

    There was a discussion on the mailing list about conversions and underlying types in 2011, and a proposal to allow conversion between recursively equivalent types in 2016 which was declined "until there is a more compelling reason".

    点赞 打赏 评论

相关推荐 更多相似问题