В предыдущих частях я пояснял, что простыми типами можно свободно манипулировать, и даже превращать их в указатели и обратно.
Оставалось обсудить сложные типы, кототорые живут в высокоуровневых языках. Высокий уровень – это значит по максимуму cпрятать от нас всю работу с памятью и создать уютный мирок из красивых абстракций, где всё логично, просто и строго. Строго – значит мы будем ограничены почти во всём. За этим будет следить уже сам язык.
Объявили переменную char или String – извольте записывать в неё строго символы. Кроме того, если сложить две переменные символьного типа, то в языке С это будет эквивалентно сложению двух чисел и получится просто какое-то новое число (и какой-то новый символ). Да вот даже натурный эксперимент:
'A' + 'B' = 65+66 = 131 = 'Г'
А в JavaScript или Python получится:
'A' + 'B' = 'AB'
Тут своя логика: если складываются два символа или две строки, то значит их надо соединить. Это уже не числа, а именно строки. И нам, людям, так гораздо привычнее, конечно. И скорее всего, мы именно так и хотели складывать символы. Можно даже написать:
"Hello " + "world"
На языке C такая операция просто не имеет смысла, а вот JavaScript и Python спокойно сложат строки и мы получим "Hello world". Правда, чтобы это сделать, им придется выделить память под новую строку и по очереди скопировать в неё содержимое двух исходных строк, так как строки не являются простыми типами. Но это всё будет проделано скрытно от нас, и мы увидим только простой и понятный результат. На то она и высокоуровневость. А в языке C пришлось бы сделать то же самое, но руками и функцией strcpy(). От этого никуда не деться, просто вопрос, кто будет это делать – мы или язык.
Любые массивы, строки, классы и прочее – всё становится самостоятельными, отдельными типами с жестко назначенным для них поведением, которое вы не можете изменить. Менять его и не надо – всё сделано для вашего удобства. В конце концов, складывать строки руками – неудобно.
Массив становится целым классом Array, а что есть у класса? Свойства и методы. Например, возьмем массив в Javascript:
var a = new Array();
Мы создали объект класса Array, и помимо обычного массивного доступа он дает нам возможность пользоваться своими свойствами и методами:
- a.length - длина массива
- a.push() - добавить новый элемент в массив
- a.pop() - удалить элемент из массива
- a.fill() - заполнить массив чем-то
и многое другое.
По сравнению с обычным массивом это целый звездолет, который дает нам высокий уровень культуры обслуживания.
Но тут появляется и обратная сторона. Чем сильнее вы абстрагируетесь от компьютерной архитектуры, чем больше заворачиваете ваши данные в различные представления и классы, тем больше проблем возникает, когда вам нужна высокая производительность или тонкий доступ к данным. Это критично в том числе и для игр.
Как завести число длиной 1 байт? Никак. Если в JavaScript вы написали:
var a = 5;
У вас нет никакого способа сказать, что это число должно быть байтом. Оно будет таким, каким решит язык.
Если у вас возникает необходимость работать с точной длиной данных, или перегонять числа в символы и обратно, рассмотрите следующие возможности:
- Узнайте, какие вспомогательные функции есть в языке. Например, функция char() переводит число в символ. А функция ord() наоборот переводит символ в число. В языке PHP есть функция pack(), которая позволяет построить бинарную строку из данных любого формата.
- Узнайте, что умеет сам тип (класс), с которым вы работаете. Если это класс String, то посмотрите, какие у него есть методы (например, charAt(), getBytes() и т.д.) и чем они могут помочь. Может быть и так, что вам надо записать строку задом наперед, а у неё уже есть готовый метод reverse().
- Используйте битовые маски для получения нужных вам байт из числа. Например, выражение a & 255 вернёт вам младший байт, а (a >> 8) & 255 – старший.
- В последнее время в некоторых языках озаботились производительностью и ввели дополнительные "простые" типы, которые ничем не перегружены. Скажем, в JavaScript это байтовый массив Uint8TypeArray. В Питоне тоже есть нечто подобное. Для повышения производительности по возможности используйте эти типы, а не стандартные.