[Golang] Ir uso eficiente del puntero

Ir puntero de dos maneras, una es UIntPtr tipo incorporado, es esencialmente un número entero, y el otro se proporciona paquete inseguro puntero que indica puntero puede apuntar a cualquier tipo. UIntPtr utiliza normalmente para calcular un puntero, ya que es un número entero, es fácil de calcular la posición de un puntero a la siguiente, y unsafe.Pointer utiliza para puentear, para diferentes tipos de punteros cada uno de conversión.

Ir unsafe.Pointer y también proporciona el uso algunas pautas UIntPtr.

Con estos conceptos básicos, ¿cómo podemos jugar?

Por lo general, vamos a byte [] se convierte en una cadena de hacerlo:

b := byte[]("Peppa")
string(b)

De esta manera no es un problema que va a asignar memoria y copiar una manera más eficiente no debe asignar cualquier memoria, la conversión del tipo de la memoria original.

es esencialmente una estructura de rebanada, que contiene un puntero que apunta a la matriz subyacente y Len, miembros de tapa, se pueden ver a través de la rebanada reflejan paquete está representado por:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

Los datos que es un puntero al primer elemento de la matriz subyacente. La razón por la rodaja de bytes se puede convertir en la cadena original en la cadena porque la memoria es más parecido a la estructura y la rebanada, reflejar paquete puede ser visto a través de esta cadena está representado por:

type StringHeader struct {
    Data uintptr
    Len  int
}

Así que sólo construimos StringHeader en él en la memoria original.

sh := reflect.StringHeader{
    uintptr(unsafe.Pointer(&b[0])),
    len(b),
}

Los puntos de datos que es el primer elemento de la rebanada, longitud Len de la rebanada. Tal como se usa en el presente documento unsafe.Pointer sido puenteada.
StringHeader creado objetos, el siguiente paso es para convertirlo en un objeto de tipo cadena, cómo hacerlo? O puenteado por unsafe.Pointer.

*(*string)(unsafe.Pointer(&sh))

StringHeader primera tipo de puntero a la conversión unsafe.Pointer, y luego se convierten en unsafe.Pointer tipo puntero de cadena, un valor finalmente obtenida por el valor del puntero actual.
Este tipo de conversión es por medio unsafe.Pointer en paquete inseguro también describe, en el que los ejemplos dados es la Float64bits Método paquete de matemáticas:

func Float64bits(f float64) uint64 {
    return *(*uint64)(unsafe.Pointer(&f))
}

Podemos comprobar si dos maneras de volver a asignar la memoria.

import (
    "github.com/davecgh/go-spew/spew"
    "unsafe"
    "reflect"
    "fmt"
)

func byteToString(b []byte) string {
    return string(b)
}

func byteToStringNoAlloc(b []byte) string {
    if len(v) == 0 {return ""}
    sh := reflect.StringHeader{uintptr(unsafe.Pointer(&b[0])), len(b)}
    return *(*string)(unsafe.Pointer(&sh))
}

func main() {
    b := []byte("Peppa")
    fmt.Println("切片第一个元素: ", spew.Sdump(&b[0]))

    str := byteToString(b)
    sh := (*reflect.StringHeader)(unsafe.Pointer(&str))
    fmt.Println("分配内存的方式: ", spew.Sdump(sh))

    strNoAlloc := byteToStringNoAlloc(b)
    shNoAlloc := (*reflect.StringHeader)(unsafe.Pointer(&toStr))
    fmt.Println("不分配内存的方式: ", spew.Sdump(shNoAlloc))
}

Aquí Insertar imagen Descripción
Esto da lugar a un problema más grave, de datos en la memoria puede en cualquier momento puede reciclar porque UIntPtr no es seguro, por lo que cuando se recupera la parte de la memoria, que puede ser convertido para funcionar en la memoria original llevar al pánico, por lo que de esta manera estar alerta.

insegura paquete también proporciona stringHeader seguro y sliceHeader, pero no están expuestos, así que no tenía manera de evitar que la memoria no está siendo reciclado fundido.

Publicados 360 artículos originales · elogios ganado 14 · Vistas de 100.000 +

Supongo que te gusta

Origin blog.csdn.net/LU_ZHAO/article/details/105332760
Recomendado
Clasificación