【问题标题】:How to convert a slice to alias slice in go? [closed]go - 如何将切片转换为别名切片? [关闭]
【发布时间】:2018-10-27 09:59:24
【问题描述】:

我将 int 别名为 Int。

我想将 Int 的 slice 转换为 int 的 slice,但出现编译错误:

cannot convert c (type []Int) to type []int我该如何解决这个问题?谢谢。

package main

import (
    "fmt"
)

type Int int

func main() {
    var c = []Int{}
    var x = []int( c )
    fmt.Println(len(x))
}

【问题讨论】:

  • 你所做的不是别名。您不需要别名。忘记那个词。参加 Go 之旅,了解如何转换具有相同基础类型的类型。

标签: go type-conversion slice


【解决方案1】:

您的Int 类型不是int 的别名,它是一个新类型,int 是它的基础类型。语言规范不支持/允许这种类型的转换。更具体地说,不允许将切片类型转换为元素类型不同的另一个切片类型。

安全的方式

如果您只需要[]Int[]int“视图”,“转换”的安全方法是创建[]Int 切片的副本,但类型为[]int,并使用for range 循环并将每个单独的元素从 Int 转换为 int 类型:

var c = []Int{1, 2}

x := make([]int, len(c))
for i, v := range c {
    x[i] = int(v)
}
fmt.Println(x)

输出(在Go Playground 上试试):

[1 2]

不安全的方式

还有一种“不安全”的方式:

var c = []Int{1, 2}

var x []int = *(*[]int)(unsafe.Pointer(&c))
fmt.Println(x)

输出是一样的。在Go Playground 上试试这个。

这里发生的是c的地址(也就是&c)转换成unsafe.Pointer(所有指针都可以转换成这个),然后再转换成*[]intunsafe.Pointer可以被转换为任何指针类型),然后这个指针被取消引用,它给出了一个[]int类型的值。在这种情况下它是安全的,因为[]Int[]int 的内存布局是相同的(因为Int 具有int 作为其底层类型),但一般情况下,应尽可能避免使用包unsafe .

如果Int 是“真”别名

请注意,如果 Intint 的“真实”别名,则甚至不需要转换:

var c = []Int{1, 2}

var x []int = c
fmt.Println(x)

输出与上面相同(在Go Playground 上尝试)。之所以这样是因为写[]Int和写[]int是一样的,它们是同一种类型,所以你甚至不需要在这里转换。

使用切片类型

另请注意,如果您要创建一个以[]int 作为其基础类型的新类型,则可以使用类型转换:

type IntSlice = []int

func main() {
    var c = IntSlice{1, 2}

    var x []int = []int(c)
    fmt.Println(x)
}

输出再次相同。在Go Playground 上试试这个。

【讨论】:

  • 反对者是否愿意发表评论?
  • 这个答案对我来说似乎很好。是的,downvoter 应该放下他的观点,我赞成它来弥补:) p.s.:我注意到你后来在你的答案中添加了一部分,顺便说一下我也说明了
  • “不安全”的解决方案没有什么不安全的地方。
  • @segfault 当前版本没有什么“不安全”的。 Go 向后兼容性保证不保证使用包 unsafe 的应用程序将继续在未来版本和所有平台上工作。这种不安全的解决方案不太可能在未来的版本中中断,但不能保证。可以保证,在未来的版本中,安全方式也将继续在所有平台上运行。
  • 如果过去的设计决策有任何迹象,我不会放过它们。
【解决方案2】:

问题是你没有创建 Int 作为别名,这样做

type Int int

将创建Int 作为一个不能与int 互操作的 类型。

Int 创建为别名的正确方法是

type Int = int

进行此更改后,您的程序就可以了。

【讨论】:

  • 我不知道为什么不赞成,@johlo 的回答确实展示了如何在 Go(Go 1.9 及更高版本)中创建别名。没有其他人提到 Go 中存在真正的别名。见这里:golang.org/doc/go1.9#language
【解决方案3】:

从技术上讲,type Int int 没有定义alias,而是一个全新的类型。尽管 Intint 现在有相同的 underlying types 并且可以相互转换,但这不适用于切片。更多关于允许转换的信息请参见spec

【讨论】:

    【解决方案4】:

    实际上,切片 a 只是指向指定类型的底层数组(在这种情况下,类型不同,Intint)。因此,除非您的基础类型相同,否则转换将不起作用。只是为了说明这一点,这样的事情会起作用:

    package main
    
    import (
        "fmt"
    )
    
    type Int int
    type IntSl []int
    
    func main() {
        var c = IntSl{2, 3, 4}
        var x []int
        x = []int(c)
        var a Int
        var b int
        a = 1
        b = int(a)
        fmt.Println(len(x), a, b, c)
    }
    

    游乐场:https://play.golang.org/p/ROOX1XoXg1j

    正如@icza 指出的那样,有unsafe 方式,当然,您总是可以对每个可能很昂贵的元素进行循环循环。

    【讨论】:

      猜你喜欢
      • 2017-02-19
      • 2022-01-19
      • 2021-08-18
      • 2018-09-15
      • 2021-09-04
      • 1970-01-01
      • 2019-07-12
      • 2012-02-25
      • 1970-01-01
      相关资源
      最近更新 更多