【问题标题】:Use pointer to a value as a slice使用指向值的指针作为切片
【发布时间】:2012-08-21 06:13:11
【问题描述】:

是否可以将指向某个值的指针转换为切片?

例如,我想将io.Reader 中的单个字节读入uint8 变量。 io.Reader.Read 接受切片作为其参数,因此我不能像在 C 中那样简单地为它提供指向我的变量的指针。

我认为从指针创建长度为 1、容量为 1 的切片是安全操作。显然,它应该与从长度为 1 的数组创建切片相同,这是允许的操作。有没有一种简单的方法可以用普通变量来做到这一点?或者也许我不明白某些事情并且有理由禁止这样做?

【问题讨论】:

    标签: pointers go slice


    【解决方案1】:

    切片不仅仅是一个指针,就像 C 中的数组一样,它还包含数据的长度和容量,如下所示:

    struct {
      ptr *uint8
      len int
      cap int
    }
    

    所以,是的,您需要创建一个切片。创建var a uint8 切片的最简单方法是[]uint8{a}

    a := uint8(42)
    fmt.Printf("%#v\n", []uint8{a})
    

    (但是在重新阅读您的问题后,这并不是一个解决方案)

    但是如果你想从变量创建切片,指向相同的内存空间,你可以使用unsafe 包。这是最有可能被劝阻的。

    fmt.Printf("%#v\n", (*[1]uint8)(unsafe.Pointer(&a))[:] )
    

    【讨论】:

    • 是的,我想使用切片来提供对变量的访问。所以如果不采用不安全的方法就不可能做到这一点?
    • Go 不允许在 uint8 和 [1]uint8 之间进行转换(这对我来说听起来很安全)。所以,据我所知,unsafe 是唯一的方法。如果我错了,我自己对更好的解决方案感到好奇。
    • 我的回答是直接的问题:“有没有可能……”,是的,是的。但实际上,我也建议使用 jnml 的解决方案。
    【解决方案2】:

    与其使这个琐碎的任务(过度)复杂化,为什么不使用简单的解决方案呢? IE。传递 .Read 一个长度为 1 的切片,然后将其第零个元素分配给您的变量。

    【讨论】:

    • 这就是我现在正在做的事情。我就是想知道不定义切片变量有没有更好看的方案。
    • 也许使用 [1]uint8 数组而不是 uint8 变量。然后它将适合 io.Reader。
    【解决方案3】:

    当我想向io.Reader 提供一个变量时,我找到了一种方法来克服我的情况。 Go 标准库很棒!

    import (
        "io"
        "encoding/binary"
    )
    
    ...
    
    var x uint8
    binary.Read(reader, LittleEndian, &x)
    

    作为副作用,这适用于任何基本类型,甚至适用于某些非基本类型。

    【讨论】:

    • 不错的发现! Go 开发人员肯定为我们创建了一组非常有用的包。
    • 您是否意识到您正在(间接地)使用 pass by interface{}、反射和类型断言?这是一场寻找尽可能慢的方法的竞赛,以避免可能用于简单分配的大约 2 个左右的 CPU 指令?
    • 是的,我确实意识到这里使用了接口间接。我现在不追求表现,我一直在寻找惯用的解决方案,一路上找到不同的东西。这是我发现的,我只是希望它对某人有用。
    猜你喜欢
    • 2015-05-01
    • 1970-01-01
    • 2021-05-03
    • 2017-07-31
    • 2015-02-21
    • 1970-01-01
    • 2020-05-10
    相关资源
    最近更新 更多