likes
comments
collection
share

golang面试题:字符串转成byte数组,会发生内存拷贝吗

作者站长头像
站长
· 阅读数 81

在一个公众号上看到一个这个题 虽然知道会发生拷贝, 但不知道还有这种方式来解决,转载一下以作记录。

我们知道字符串转成切片,会产生拷贝。严格来说,只要是发生类型强转都会发生内存拷贝。那么问题来了。 频繁的内存拷贝操作听起来对性能不大友好。有没有什么办法可以在字符串转成切片的时候不用发生拷贝呢?

package main\
\
import (\
 "fmt"\
 "reflect"\
 "unsafe"\
)\
\
func main() {\
 a :="aaa"\
 ssh := *(*reflect.StringHeader)(unsafe.Pointer(&a))\
 b := *(*[]byte)(unsafe.Pointer(&ssh))  \
 fmt.Printf("%v",b)\
} 
  • StringHeader 是字符串在go的底层结构。
type StringHeader struct {
 Data uintptr
 Len  int
}
  • SliceHeader 是切片在go的底层结构。
type SliceHeader struct {
 Data uintptr
 Len  int
 Cap  int
}
  • 那么如果想要在底层转换二者,只需要把 StringHeader 的地址强转成 SliceHeader 就行。那么go有个很强的包叫 unsafe 。
    • 1.unsafe.Pointer(&a)方法可以得到变量a的地址。
    • 2.(*reflect.StringHeader)(unsafe.Pointer(&a)) 可以把字符串a转成底层结构的形式。
    • 3.(*[]byte)(unsafe.Pointer(&ssh)) 可以把ssh底层结构体转成byte的切片的指针。
    • 4.再通过 *转为指针指向的实际内容。

补充:

float 类型可以作为 map 的 key 吗

任何类型都可以作为 value,包括 map 类型。 但是当用 float64 作为 key 的时候,先要将其转成 unit64 类型,再插入 key 中。

具体是通过 Float64frombits 函数完成:

// Float64frombits returns the floating point number corresponding
// the IEEE 754 binary representation b.
func Float64frombits(b uint64) float64 { 
return *(*float64)(unsafe.Pointer(&b)) 
}

也就是将浮点数表示成 IEEE 754 规定的格式。如赋值语句:

0x00bd 00189 (test18.go:9)      LEAQ    "".statictmp_0(SB), DX0x00c4 00196 (test18.go:9)      MOVQ    DX, 16(SP)0x00c9 00201 (test18.go:9)      PCDATA  $0, $20x00c9 00201 (test18.go:9)      CALL    runtime.mapassign(SB)

"".statictmp_0(SB) 变量是这样的:

"".statictmp_0 SRODATA size=8        0x0000 33 33 33 33 33 33 03 40"".statictmp_1 SRODATA size=8        0x0000 ff 3b 33 33 33 33 03 40"".statictmp_2 SRODATA size=8        0x0000 33 33 33 33 33 33 03 40

我们再来输出点东西:

package mainimport (    "fmt"    "math")
func main() {    
m := make(map[float64]int)    
m[2.4] = 2   
fmt.Println(math.Float64bits(2.4))   
fmt.Println(math.Float64bits(2.400000000001))    
fmt.Println(math.Float64bits(2.4000000000000000000000001))}
461258673835286200346125867383528642554612586738352862003

转成十六进制为:

0x40033333333333330x4003333333333BFF0x4003333333333333

和前面的 "".statictmp_0 比较一下,2.4 和 2.4000000000000000000000001 经过 math.Float64bits() 函数转换后的结果是一样的。自然,二者在 map 看来,就是同一个 key 了。

转载自:https://juejin.cn/post/7048508847647883271
评论
请登录