«Go»: указатели и арифметика
Одна из особенностей «Go», о которой пишут в большинстве статей по языку, это наличие в языке указателей, но отсутствие арифметики с ними. Вот, например, цитата из статьи «Go For C++ Programmers»:
Go has pointers but not pointer arithmetic. You cannot use a pointer variable to walk through the bytes of a string.
В самом деле, если попробовать скомпилировать следующий пример, то нас ждёт неудача:
package main
func main() {
var pointer *[]uint8 = new([]uint8)
pointer++ // invalid operation: pointer += 1 (mismatched types *[]uint8 and int)
}Никакими преобразованиями базовых типов не добиться чтобы язык разрешил прибавить хоть
В модуле «unsafe» есть специальный тип «Pointer», в руководстве по использованию которого написано следующее:
1) A pointer value of any type can be converted to a Pointer.
2) A Pointer can be converted to a pointer value of any type.
3) A uintptr can be converted to a Pointer. 4) A Pointer can be converted to a uintptr.
В свою очередь, uintptr встроен в язык и это не указатель, это обычный числовой тип, пусть вас не смущает слово «ptr». Указатель напрямую нельзя преобразовать к типу uintptr или обратно, но можно это сделать через unsafe.Pointer, как видно из цитаты выше.
И вот что получается:
package main
import "fmt"
import "unsafe"
func main() {
e := [...]uint8{11,22,33} // создаю массив из трёх байт — 1, 2, 3
p := &e[0] // p — указатель на первый элемент массива (тип *uint8)
fmt.Println(*p) // выводит «11»
p = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) // указатель преобразован в число, прибавляется «1», преобразуем обратно в указатель
fmt.Println(*p) // выводит «22»
s := "12345" // строка, содержащая «12345»
*(*uintptr)(unsafe.Pointer(&s))++ // сдвигаем адрес, на который ссылается «s»
fmt.Println(s, len(s)) // «2345», но длина всё равно 5 (!), в последнем байте неотображаемый символ
}
Комментарии 10
Ну модуль же называется unsafe =)
Часто такое вижу, когда на ruby пишут как на C++ или как на Java, вроде код на Ruby, а все таки не на Ruby
Я не знаю C++. Я не пытаюсь писать на этом языке как на C++ иличём-то подобном. Это статья просто показывает, что арифметики нет, но если очень надо, то она есть.
тогда-то я и научился сдвигать указатель.
Мне это уже один раз понадобилось ( /all/3197 ), когда я вызвал syscall ioctl, которому нужно было передать структуру, которую «Go» сдвигал на 4 байта в памяти (выравнивал по границе 8 байт). Вот
P.S. Кстати, прикрутил бы к своему блогу OpenID, это же просто ( /all/1514 ) и подписывался бы им?
А длина строковой переменной вероятно на единичку больше
Для собственного сайта лучше использовать pavatar, мне кажется ( http://pavatar.com/ ).
Надо было всего лишь delegate сделать :)
То есть, если сдвинуть указатель на произвольное место, то там будет
Haskell возможно будет следующим.
Clojure — это Лисп, с Лиспом я баловался немного.
О Scala не задумывался, присмотрюсь, единственное, что меня смущает, говорят, что он похож на Java.
Мне вот clojure не понравилась, но кажется что это
А Scala хороший язык, очень хороший. На голову выше Java.
Буду ждать с нетерпением постов про хаскелл! :)
Комментарий для anonymous:
Во-первых, мне в кои-то веки захотелось что-нибудь компилируемого, я давно ничего не пишу на компилируемых языках (редкое баловство с Си не считается)
Во-вторых, мне очень понравилось как язык легко обходится с многозадачностью
В-третьих, GC в компириемом языке, для меня это что-то необычное
В-четвёртых, Ваня Сагалаев этот язык очень хвалил в разговоре, а у меня, напротив, впечатление было так себе, решил узнать что он в нём нашёл :)
Я так и не сказал почему именно Go.
Это не раньше чем пойму, что знаю «Гоу» на крепком среднем уровне. У меня там несколько пробелов даже на уровне языка, не говоря уже окаком-то мышлении в рамках этого языка или понимания кишок, доступных программисту.