Преобразование между указателями

Преобразование между указателями разных типов в Go выполняется с помощью типа unsafe.Pointer. Это специальный тип, который позволяет обойти систему типов Go и выполнять преобразования между указателями на разные типы данных. unsafe.Pointer может быть преобразован в указатель любого типа и обратно, но использование этого механизма требует особой осторожности, так как он может привести к неожиданному поведению программы.

Синтаксис

gounsafe.Pointer(&var)

Пример

Давайте преобразуем указатель на int в указатель на float64 с помощью unsafe.Pointer:

gopackage main

import (
  "fmt"
  "unsafe"
)

func main() {
  num := 42
  intPtr := &num
  floatPtr := (*float64)(unsafe.Pointer(intPtr))

  fmt.Printf("int: %d, float: %f\n", num, *floatPtr)
}

Результат выполнения кода:

go"int: 42, float: 0.000000"

В результате мы получили указатель на float64, который указывает на ту же область памяти, что и исходный указатель на int. Однако значение интерпретируется по-другому, поэтому результат может быть неожиданным.

Пример

Давайте преобразуем указатель на int в указатель на int64 и обратно:

gopackage main

import (
  "fmt"
  "unsafe"
)

func main() {
  num := 100
  intPtr := &num

  int64Ptr := (*int64)(unsafe.Pointer(intPtr))
  fmt.Printf("int64: %d\n", *int64Ptr)

  newIntPtr := (*int)(unsafe.Pointer(int64Ptr))
  fmt.Printf("int: %d\n", *newIntPtr)
}

Результат выполнения кода:

go"int64: 100"
"int: 100"

При преобразовании указателя на int в указатель на int64 мы получаем доступ к тем же данным, но интерпретируемым как 64-битное целое число. Обратное преобразование восстанавливает исходный тип.

Пример

Давайте используем unsafe.Pointer для работы со структурой разных типов:

gopackage main

import (
  "fmt"
  "unsafe"
)

type User struct {
  ID   int
  Name string
}

type Raw struct {
  ID   int
  Name string
}

func main() {
  user := User{ID: 1, Name: "John"}
  userPtr := &user

  rawPtr := (*Raw)(unsafe.Pointer(userPtr))
  fmt.Printf("Raw: %+v\n", *rawPtr)
}

Результат выполнения кода:

go"Raw: {ID:1 Name:John}"

Мы можем преобразовывать указатели на структуры с одинаковым расположением полей в памяти, даже если имена типов различаются.

Смотрите также