Skip to content

Latest commit

 

History

History
239 lines (153 loc) · 17.8 KB

tipy-dannykh.md

File metadata and controls

239 lines (153 loc) · 17.8 KB

Типы данных

Строки

Строковый тип данных - string. Строки в Vala статичны и кодируются в UTF-8.

string text = "Не изменяемая строка";

Vala предоставляет функцию называемую "дословная строка". Это строки в которых управление выводом при помощи управляющих последовательностей (таких как \n) не учитывается, переводы линий сохраняются и кавычки не нужно маскировать. Они заключены в тройные кавычки. Возможные отступы являются частью строки

string verbatim = """Это так называемая дословная строка "verbatim string".
Такие строки не распознают управляющие последовательности, такие как \n, \t, \\, и другие.
Они могут содержать кавычки и состоять из нескольких строк.""";

Строки, начинающиеся с '@' - строковые шаблоны. Они могут вычислять встроенные переменные и выражения начинающиеся с '$'

int a = 6, b = 7;
string s = @"$a * $b = $(a * b)"; // => "6 * 7 = 42"

Операторами сравнения == и != сравнивается содержимое двух строк, в отличии от Java, где просто проверяются ссылочные равенства.

Вы можете получить часть строки используя синтаксис [индекс_начала:конечный_индекс]. При отрицательном значении индекса позиция вычисляется с конца строки:

string greeting = "Привет, мир!";
string s1 = greeting[8:12]; // => "мир!"
string s2 = greeting[-12:-6];; // => "Привет"

Обратите внимание на то, что индексы в Vala начинаются с 0, так же, как и в большинстве других языков программирования. Вы можете обратиться к любому символу Unicode в строке, используя [индекс_элемента]:

unichar c = greeting[8]; // => 'м'

Однако вы не можете присвоить новый символ в эту позицию, так как в Vala строки неизменяемы. Также обратите внимание, что это не просто доступ к массиву символов. Строка разбивается на символы внутренними методами, потому что в кодировке UTF-8 каждый символ может занимать различное количество байт.

В большинстве основных типов данных присутствуют удобные методы для преобразования в строку и наоборот, например:

bool b = bool.parse("false"); // => false
int i = int.parse("-52"); // => -52
double d = double.parse("6.67428E-11"); // => 6.67428E-11
string s1 = true.to_string(); // => "true"
string s2 = 21.to_string(); // => "21"

Вот два удобных метода для получения и вывода строк в консоль (и для ваших первых экспериментов с Vala), stdin.read_line() и stdout.printf():

stdout.printf("Привет, мир!\n");
stdout.printf("%d %g %s\n", 42, 3.1415, "Vala");
string input = stdin.read_line();
int number = stdin.read_line().to_int();

Вы уже знаете stdout.printf() из примера Hello World. Вообще-то, он (stdout.printf) может принимать произвольное число аргументов разных типов, где первый аргумент форматная строка, правила составления которой такие же как в C. Если вам необходимо вывести сообщение об ошибке вы можете использовать stderr.printf() вместо stdout.printf()

Массивы

Массив объявляется используя следующий синтаксис: тип, после него [] и используется оператор new.

Например int[] a = new int[10] для создания массива целых чисел. Узнать длину массива можно при помощи свойства length, т.е. int count = a.length. Учтите, что если вы напишите Object[] a = new Object[10] будут созданы не объекты, а массив для их хранения.

int[] a = new int[10];
int[] b = { 2, 4, 6, 8 };

Вы можете получить под-массив используя разделение (как в примере со строками) [индекс_начала:конечный индекс_]:

int[] c = b[1:3]; // => { 4, 6 }

Разделение массива возвращает новый массив. Изменение этого под-массива не повлияют на оригинальный массив

Многомерные массивы объявляются с помощью [,] или [,,] и т. д.

int[,] c = new int[3,4];
int[,] d = {{2, 4, 6, 8},

{3, 5, 7, 9},
{1, 3, 5, 7}};
d[2,3] = 42;

Такой массив является блоком памяти. Невыровненные массивы (так же известные как "стек массивов" или "массив массивов"), где строки массива могут отличаться размером, пока что не поддерживается.

Для того, чтобы определить размер многомерного массива, можно использовать функцию length указывая в квадратных скобках ту размерность, размер которой желаете узнать.

int[,] arr = new int[4,5];
int r = arr.length[0];
int c = arr.length[1];

Вы можете динамически добавлять элементы в массив, используя оператор +=. Стоит заметить, что это работает только для локально объявленных или для приватных массивов. При необходимости массивы автоматически перераспределяются. Перераспределение возводит размер в степень двойки, тем самым, эффективно улучшая время исполнения. При этом, функция .length отображает фактическое количество элементов, а не размер массива.

int[] e = {}

e += 12;
e += 5;
e += 37;

Вы можете изменить размер массива вызвав функцию resize(). При этом содержимое массива не изменится.

int[] a = new int[5];
a.resize(12);

Если вы поместите значение в квадратные скобки после идентификатора, вы получите массив фиксированного размера. Массивы фиксированного размера будут помещены в стек (если массив объявлен локальной переменной), или подключен (если массив используется в качестве полей) и вы не сможете перераспределить их.

int f[10]; // без 'new ...'

Vala не делает проверки границ массива во время выполнения. Если вы желаете обезопасить свою программу от выхода за пределы массива, тогда вам следует использовать более сложные структуры данных, к примеру ArrayList. Об этом можно более подробно прочесть в разделе "коллекции"

Ссылочные типы

К ссылочным типам относятся все типы объявленные как классы, независимо от того, являются ли они потомками Object из GLib или нет. Vala будет гарантировать, что когда вы передаете объект по ссылке, система будет отслеживать количество "живых" ссылок, чтобы автоматически управлять памятью. Значение ссылки, которая не указывает ни на один объект - null. Больше о классах читайте в разделе об объектно-ориентированном программировании.

/ определяем класс /

class Track : GLib.Object { / потомок класса 'GLib.Object' / public double mass; / открытое поле / public double name { get; set; } / открытое свойство / private bool terminated = false; / закрытое поле / public void terminate() { / открытый метод / terminated = true; } }

Статическое приведение типов

В Vala вы можете привести переменную одного типа к другому типу. Для статического приведения типов используется имя нового типа в круглых скобках. Статическое приведение не предполагает какой-либо проверки безопасности типов во время выполнения программы. Оно работает для всех типов Vala. Например,

int i = 10;
float j = (float) i;

Vala поддерживает другой механизм приведения типов - динамическое приведение, которое выполняет проверку типов во время выполнения. Этот механизм описан в разделе об объектно-ориентированном программировании.

Вывод типов (Type Inference)

В Vala есть механизм вывода типа, когда локальная переменная может быть определена с помощью ключевого слова var вместо указания типа, если подразумеваемый тип может быть точно определен. Тип выводится по правой части в операции присваивания. Этот механизм помогает сократить ненужную избыточность кода без ущерба для статической типизации.

var p = new Person(); // то же самое, что: Person p = new Person();
var s = "hello"; // то же самое, что: string s = "hello";
var l = new List<int>(); // то же самое, что: List<int> l = new List<int>();
var i = 10; // то же самое, что: int i = 10;

Этот механизм работает только для локальных переменных. Предполагаемый тип особенно полезен для типов с аргументами общего типа (больше о них читайте дальше). Сравните

MyFoo<string, MyBar<string, int>> foo = new MyFoo<string, MyBar<string, int>>();

и

var foo = new MyFoo<string, MyBar<string, int>>();

Операторы

=

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

+, -, /, *, %

простые арифметические операции, применяемые к левому и правому операндам. Оператор + также может объединять строки.

+=, -=, /=, *=, %=

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

++, --

операции инкремента и декремента с неявным присваиванием. Они принимают один аргумент, который должен быть переменной простого типа. Значение будет изменено и присвоено той же переменной. Эти операции могут быть префиксными и постфиксными - в префиксной форме в выражении будет использоваться новое вычисленное значение переменной, в постфиксной - значение в настоящий момент.

|, ^, &, ~, |=, &=, ^=

побитовые операции: ИЛИ, исключающее ИЛИ, И, НЕ. Действие оставшихся операций аналогично арифметическим. Они могут быть применены только к простым типам. (Нет оператора присваивания, ассоциированного с ~, потому что это унарный оператор. Эквивалентный оператор a = ~a).

<<, >>

операторы сдвига битов, сдвигают биты левого операнда на число, заданное правым операндом.

<<=, >>=

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

==

проверка равенства. Возвращает логическое значение в зависимости от того, равны ли левый и правый операнды. В случае значимых типов это значит, что их значения равны; в случае ссылочных типов - то, что ссылки указывают на один и то же экземпляр объекта. Исключением из этого правила являются строки, которые проверяются на равенство по значению.

<, >, >=, <=, !=

проверка неравенства. Возвращают логическое значение в зависимости от отношения левого и правого операндов. Применимы к простым типам и строкам. Для строк сравнение производится в лексикографическом порядке.

!, &&, ||

логические операции: НЕ, И, ИЛИ. Эти операции могут применяться к логическим значениям. Первая принимает только один аргумент, другие - два.

? :

тернарный условный оператор. Проверяет условие и возвращает левую или правую часть подвыражения в зависимости от значения, возвращаемого условием: <условие> ? <значение, если условие true> : <значение, если условие false>

??

Оператор проверки на null: a ?? b эквивалентно коду a != null ? a : b. Этот оператор удобен для предоставления значения по умолчанию, если ссылка не действительна (ни на что не ссылается).

stdout.printf("Привет, %s!\n", name ?? "неизвестная личность");

in

проверяет, содержит ли правый операнд левый операнд. Этот оператор работает с массивами, строками, коллекциями и другими типами, у которых есть соответствующий метод contains(). Для строк он производит поиск подстроки.

if ("Привет" in "Привет мир!") print("Yes!");
int[] arr = {0,1,2,3};
if (2 in arr) print("Yes!");

В Vala операторы не могут быть перегружены. Существуют дополнительные операторы, которые действуют в контексте определений лямбда-функций и других особых задач - их объяснение будет дано в контексте их применения.