¿Cómo usar unsafe.Pointer en la programación del lenguaje Go en tiempo de ejecución?

Ir idioma gran fábrica programación inseguro puntero inseguro

Convertir la estructura de datos aunsafe.Pointer

func Unsafe1() {
   var m = map[int]int{
      2: 10086,
      3: 10087,
   }
   pointer := unsafe.Pointer(&m)
   fmt.Println(*(*map[int]int)(pointer))
}
复制代码

Producción:

mapa[2:10086 3:10087]

Aquí se mconvertirá en unsafe.Pointer, y luego lo volveremos a convertir manualmente ( (*map[int]int)(pointer))), y luego lo desreferenciaremos para eliminar el contenido que contiene.

Encuentre la especificidad de los tipos de interfaz interfacevacíos

func Unsafe2() {
   var m = map[int]int{
      2: 10086,
      3: 10087,
   }

   var i = func(v any) {//ps:笔者这里用1.18的版本,用了关键字`any`替换
      pointer := unsafe.Pointer(&v)
      fmt.Println(*(*map[int]int)(pointer))
   }
   i(&m)
}
复制代码

Cuando ejecute este código, no será tan normal como el código de Unsafe1 , sino un mensaje de error anormal Salida:

dirección de falla inesperada 0x225d error fatal: falla [señal SIGSEGV: código de violación de segmentación = 0x1 addr = 0x225d pc = 0x100d4c0]

goroutine 1 [en ejecución]: runtime.throw({0x10a1a5d?, 0x1741118?}) /Users/gre/Go/go1.18/src/runtime/panic.go:992 +0x71 fp=0xc000092a20 sp=0xc0000929f0 pc=0x102f411 tiempo de ejecución .sigpanic() ...

Esto implica interfacela lógica de conversión de tipo de Interfaz diseño de interfaz eface

En pocas palabras, nuestra estructura se convierte en tipo en el proceso de pasar parámetros, por lo que no tenemos forma de volver a convertir directamente a nuestros datos.

¿Entonces, qué debemos hacer?

func Unsafe3() {
   var m = map[int]int{
      2: 10086,
      3: 10087,
   }

   var i = func(v any) {
      type eface struct {
         rtype unsafe.Pointer
         data  unsafe.Pointer
      }
      pointer := (*eface)(unsafe.Pointer(&v))
      fmt.Println(*(*map[int]int)(pointer.data))
   }
   i(&m)
}
复制代码

Producción:

mapa[2:10086 3:10087]

Definimos efacetipos para recibir tipos y tipos de datos, y luego buscamos y dataconvertimos los datos que necesitamos.

En términos generales, a los desarrolladores no se les pide que especifiquen el tipo de información de cada dato a decodificar, sino que se implementan reflejando la estructura original.

func Unsafe4() {
   var m = map[int]int{
      2: 10086,
      3: 10087,
   }
   var (
      pointer  = unsafe.Pointer(&m)
      value1   = reflect.ValueOf(&m)
      ptrRType = *(*unsafe.Pointer)(unsafe.Pointer(&value1))
   )

   var packTAny = func(rtype unsafe.Pointer, data unsafe.Pointer) any {
      type eface struct {
         rtype unsafe.Pointer
         data  unsafe.Pointer
      }
      var i interface{}
      e := (*eface)(unsafe.Pointer(&i))
      e.rtype = rtype
      e.data = data
      return i
   }

   face := packTAny(ptrRType, pointer)
   m2 := (face).(*map[int]int)
   fmt.Println(*m2)
}
复制代码

Producción:

mapa[2:10086 3:10087]

Cómo el programa Go analiza la estructura en tiempo de ejecución

//go:noescape
//go:linkname mapiterinit reflect.mapiterinit
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer, it *hiter)

//go:noescape
//go:linkname mapiternext reflect.mapiternext
func mapiternext(it *hiter)

func Unsafe5() {
   var m = map[int]int{
      2: 10086,
      3: 10087,
   }
   var (
      value    = *(*unsafe.Pointer)(unsafe.Pointer(&m))
      value1   = reflect.ValueOf(m)
      ptrRType = *(*unsafe.Pointer)(unsafe.Pointer(&value1))
      it       hiter
   )

   mapiterinit(ptrRType, value, &it)
   for {
      key := it.key
      elem := it.value
      if key == nil {
         return
      }
      fmt.Println(*((*int64)(key)))
      fmt.Println(*((*int64)(elem)))
      mapiternext(&it)
   }
}
复制代码

Producción:

mapa[2:10086 3:10087] 2 10086 3 10087

go:linknameNecesitamos runtime.mapuna mapiterinitfunción para vincular, que se puede importar y ejecutar en tiempo de compilación.

Puede aprender algunos otros conceptos de reflexión e inseguridad aquí

  1. reflect (código oficial de la biblioteca src/reflect)
  2. reflect2 (referido como la biblioteca json-iterator/go más rápida para serializar json en go)

Supongo que te gusta

Origin juejin.im/post/7087071105835335716
Recomendado
Clasificación