Ответ
В Go, в его безопасной части, нет адресной арифметики, в отличие от C/C++. Указатели в Go спроектированы быть безопасными: они могут быть nil или указывать на действительный объект в памяти, но с ними нельзя производить арифметические операции (например, ptr++).
Однако для низкоуровневых операций, где требуется прямой доступ к памяти, существует пакет unsafe.
Пакет unsafe
Он позволяет обойти систему типов Go. С его помощью можно преобразовать указатель в тип uintptr (целочисленный тип, достаточный для хранения адреса), выполнить над ним арифметические операции, а затем преобразовать обратно в unsafe.Pointer.
Пример:
package main
import (
"fmt"
"unsafe"
)
func main() {
arr := [3]int{10, 20, 30}
// Получаем указатель на первый элемент
p := &arr[0]
// Преобразуем в unsafe.Pointer, затем в uintptr для арифметики
// uintptr - это просто число, а не указатель
addr := uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(arr[0])
// Преобразуем адрес обратно в типизированный указатель
nextP := (*int)(unsafe.Pointer(addr))
fmt.Println(*nextP) // Выведет: 20
}
Важно: Использование unsafe ломает гарантии безопасности типов и памяти в Go и может привести к непредсказуемому поведению или панике. Его следует применять только в исключительных случаях, например:
- Для критической оптимизации производительности.
- При взаимодействии с кодом на C через
Cgo. - При реализации очень низкоуровневых структур данных.
В подавляющем большинстве случаев следует использовать безопасные альтернативы, такие как срезы (slices).
Ответ 18+ 🔞
А, слушай, вот это интересный момент, про который многие, блядь, с порога заблуждаются! В Go, в его нормальном, штатном режиме — адресной арифметики нихуя нету, в отличие от этих твоих C/C++, где можно по памяти шастать как по своему огороду.
Указатели в Go — они как воспитанные дети: либо nil (ни на что не указывают), либо тыкаются в конкретный, законный объект. Сказать им ptr++, чтобы перепрыгнуть на соседнюю память — нихуя не выйдет, компилятор тебя по рукам нахуй даст.
Но, как и в любой строгой системе, блядь, есть чёрный ход. Для тех, кто готов, сука, на всё ради скорости или чтобы с легаси-кодом подружиться — есть пакет unsafe.
Пакет unsafe — откровенный гопник в мире типов
Этот пакет — он как отмычка. Позволяет, сука, обойти всю эту политкорректную систему типов Go. Алгоритм простой, как три копейки:
- Берёшь свой типизированный указатель, превращаешь его в
unsafe.Pointer(это такая серая, бестиповая хуйня). - А потом — о, магия! — конвертируешь это в
uintptr. Это уже просто число, ёпта, адрес в памяти. И вот с этим числом можно делать что угорячишь: прибавлять, вычитать — классическая арифметика, блядь. - А потом, сука, обратно собираешь:
uintptr->unsafe.Pointer-> в нужный тебе тип указателя.
Смотри, как это выглядит в деле:
package main
import (
"fmt"
"unsafe"
)
func main() {
arr := [3]int{10, 20, 30}
// Ловим указатель на первый элемент
p := &arr[0]
// Начинается магия, блядь:
// 1. Указатель -> в бестиповый unsafe.Pointer
// 2. unsafe.Pointer -> в голый адрес (uintptr)
// 3. К адресу прибавляем размер одного int'а
addr := uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(arr[0])
// А теперь собираем всё обратно, в рот меня чих-пых!
// 1. Адрес (uintptr) -> обратно в unsafe.Pointer
// 2. unsafe.Pointer -> в указатель на int (*int)
nextP := (*int)(unsafe.Pointer(addr))
fmt.Println(*nextP) // Выведет, ясное дело, 20
}
Но запомни раз и нахуй: использование unsafe — это как снять все предохранители. Гарантии безопасности памяти и типов летят в пизду. Можешь запросто наступить на грабли и получить панику, или, что хуже, тихие, ебучие corruption данных.
Применять эту темную магию стоит только в крайних случаях, когда уже припёрло:
- Для дикой, запредельной оптимизации, где каждый наносекунд на счету.
- Когда через
Cgoобщаешься с каким-нибудь древним С-шным кодом, который тебе, как проклятие, достался. - Когда пишешь свою хитровыебанную, низкоуровневую структуру данных.
А так-то, в 99.9% случаев, тебе должно хватать нормальных, человеческих срезов (slices). Не лезь туда, куда не просят, а то мало не покажется!