ПРОДВИНУТЬСЯ

Что такое unsafe.Pointer или uintptr?

unsafe.Pointer, uintptr кажутся многим разработчикам Go полной черной магией. И надо признать, они действительно волшебные, позвольте мне показать вам пример…

unsafe.Pointer, uintptr кажутся многим разработчикам Go полной черной магией. Мы часто просто используем их как специальные заклинания для пакетов, не понимая, как они работают «под капотом».

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

type Person struct {
  Name string
  age  int
}

func main() {
  person := Person{Name: "John", age: 30}
  
  // Cast name to unsafe pointer
  namePtr := unsafe.Pointer(&person.Name)
  nameSize := unsafe.Sizeof(person.Name)
  
  p := (*int)(unsafe.Add(namePtr, nameSize))
  *p = 10
  
  fmt.Println(person) // {John 10}
}

Проделав некоторые небезопасные математические вычисления с указателями, я могу изменить частное поле age через общедоступное поле Name. Этот подход совершенно неинтуитивен, но он работает, меняя возраст Джона с 30 на 10.

Понимание того, как безопасно использовать небезопасные указатели, позволяет создавать мощные функциональные возможности.

Первый взгляд на небезопасную упаковку

Помимо unsafe.Pointer, этот пакет предоставляет нам несколько функций, предоставляющих низкоуровневую информацию, позволяющую нам лучше понять внутреннюю структуру типа.

небезопасно.Alignof

Выравнивание — это концепция, пришедшая из низкоуровневого программирования. Она возвращает необходимое выравнивание типа, а расположение памяти может влиять на производительность нашего приложения.

Например, int32 имеет выравнивание в 4 байта. Выравнивание структуры зависит от поля с наибольшим выравниванием:

type Person struct {
  Name string
  age  int
}

func main() {
  var i int32 = 1
  var s [3]int8 = [3]int8{1, 2, 3}
  var p Person = Person{"Bob", 20}
  
  fmt.Println("aligno(int32) =", unsafe.Alignof(i))
  fmt.Println("alignof([]int8) =", unsafe.Alignof(s))
  fmt.Println("alignof(Person) =", unsafe.Alignof(p))
}

// aligno(int32) = 4
// alignof([3]int8) = 1
// alignof(Person) = 8