Эта страница написана в формате сайта Learn X in Y minutes где X = PascalABC.NET.
PascalABC.NET — это элегантный и типобезопасный компилируемый язык программирования, основное предназначение которого — образовательная сфера и научные исследования. PascalABC.NET позволяет создавать надёжные приложения на платформе .NET и поддерживает мультипарадигменный подход, объединяя структурный, объектно-ориентированный и функциональный стили программирования.
// Однострочные комментарии начинаются с // { Многострочные комментарии выглядят следующим образом } (* Многострочные комментарии можно также делать так *)
// Простейшая программа begin Print('Привет мир') end. // Простейшая программа в режиме без внешнего begin-end ## Print('Привет мир') // Программа с вводом-выводом begin var a := ReadInteger('Введите a:'); var b := ReadInteger('Введите b:'); var sum := a + b; Println('Сумма =', sum) end. // Вариант: begin var (a,b) := ReadInteger2('Введите a,b:'); Println($'{a} + {b} = {a + b}') // $'' - интерполированная строка Println($'{a} * {b} = {a * b}') // $'' - Println - для перехода на новую строку end.
// Print или Write Print(1,2) // 1 2 - разделяет данные пробелом Write('a','b') // ab - не разделяет данные пробелом // Print и Println, Write и Writeln Print(1,2); // без перехода на новую строку Println(1,2); // с переходом на новую строку // Аналогично Write и Writeln // Print для вывода составных структур var d := Dict('abc' to [(1,2),(3,4)], 'def' to [(5,6),(7,8)]); Print(d); // Вывод: {(abc,[(1,2),(3,4)]),(def,[(5,6),(7,8)])} // Кортежи и объекты классов и записей выводятся в (), // Массивы, списки и последовательности выводятся в [] // Множества и словари выводятся в [] // Print и вывод больших данных Print(Arr(1..200)); // Вывод обрезается до 99 элементов: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,...] // Print и вывод рекурсивных данных type Node = auto class x: integer; next: Node; end; begin var n := new Node(Random(100),nil); loop 10 do n := new Node(Random(100),n); Print(n); end. // Вывод: (42,(19,(40,(39,(63,(46,(43,(83,(66,(8,(75,nil)))))))))))
// Описание переменной с указанием типа var x: integer; // Описание переменной с указанием типа и инициализацией var x: real := 2; // Описание переменной с инициализацией и автовыводом типа var s := 'Hello'; // Описание нескольких переменных с автовыводом типа var (s1,s2) := ('Hello','World'); // Символы описываются в апострофах как и строки var c: char := 'z'; // s получит тип string var s := $'z'; // Константы описываются только до блока begin - end программы или подпрограммы const Pi = 3.14;{Переопределение существующей константы. Константа Pi уже описана в PascalABC.NET со значением Pi = 3.14159265358979} const n: integer = 100; // Переменные могут описываться до блока begin-end если используются во всей программе (редко) var i1,i2: integer; r: real; begin // В PascalABC.NET предпочтительно переменные описывать внутри блока var k: real; var n: real := 10; // предпочтительно инициализировать переменную при описании // var r: string; - ошибка - внутриблочные переменные не могут иметь те же имена что и переменные верхнего уровня end. // Многострочные строки var s := ''' Многострочная строка Открывающие и закрывающие кавычки должны быть каждая на своей строке Лидирующие пробелы слева от закрывающих кавычек удаляются во всех строках многострочной строки Внутри могут быть апострофы ' и '' но не три апострофа подряд '''; // Диапазоны и типы диапазонов 1..9 // диапазон целых IntRange 1.5 .. 2.8 // диапазон вещественных RealRange 'a'..'z' // диапазон символов CharRange // Операции in и not in для диапазонов 5 in 1..9 x not in a..b c in 'a'..'z'
Основные типы данных, операции и выражения
[править]
// Целые знаковые типы shortint (1 байт) smallint (2 байт) integer (4 байт) int64 (8 байт) Константы: 2 -555 // Целые беззнаковые типы byte (1 байт) word (2 байт) longword (4 байт) uint64 (8 байт) Константы: 2 $FFFF (шестнадцатеричная) // Операции для целых 7 div 2 // = 3 - целочисленное деление 7 mod 2 // = 1 - остаток от целочисленного деления -7 mod 2 // = -1 5 shl 1 // = 10 - побитовый сдвиг влево 5 shr 1 // = 2 - побитовый сдвиг вправо // Тип длинных целых BigInteger // Константы Константы BigInteger имеют суффикс bi: 1bi bi ** 10 // возведение в целочисленную степень // Вещественные типы real (8 байт) single (4 байт) decimal (16 байт) Константы: 2.5 1.7E-13 2.0 ** 10 // возведение в степень // Операции для всех числовых типов Математические: + - * / Сравнения: = <> > < >= <= // Логический тип boolean Константы: True False // Операции для логических and or xor (исключающее "или") not // Символьный тип (двухбайтовый, хранит Unicode) char Константы: 'a' #10 // Стандартные функции Ord(c) // код символа c c.Code // код символа c Chr(i) // символ с кодом i // Строковый тип string Константы: 'abc' $'a' // Перечислимый тип type Days = (Mon,Tue,Wed,Thi,Fri,Sat,Sun); var d: Days := Mon; // Приведения базовых типов var i: integer; r: real; c: char; s: string; begin r := i; // целые неявно преобразуются в вещественные s := c; // символьные неявно преобразуются в строковые // Явные преобразования типов с помощью методов s := i.ToString; i := s.ToInteger; // Может быть исключение s := r.ToString; r := s.ToReal; // Может быть исключение end. // Методы Print и Println для вывода базовых типов i.Print; r.Print; s.Print; c.Print; // Операции in и not in для диапазонов 5 in 1..9 x not in a..b c in 'a'..'z' // Тернарная операция в стиле C var min := x < y ? x : y; // Тернарная операция в стиле Pascal var min := if x < y then x else y; // Операция явного приведения типа // var i: integer := integer(3.56); // Результат: 3 - дробная часть отбрасывается var r := real(3); // Результат - вещественный var p := new Person; var s: Student := Student(p); // DownCast: Student - наследник Person
В стандартном модуле определен ряд функций и процедур. Здесь приводятся некоторые из них
Sqrt(x) Abs(x) Sin(x) Cos(x) Ln(x) Log10(x) ... // математические функции Round(x) // Округление вещественного до ближайшего целого Round(x,n) // Округление вещественного до ближайшего вещественного с n знаками после точки Trunc(x) // Отбрасывание дробной части, результат - integer Floor(x) // Наибольшее целое <= x Ceil(x) // Наименьшее целое >= x Odd(x) // True если x - нечетно Even(x) // True если x - четно x.Odd // True если x - нечетно x.Even // True если x - четно Random(a,b) // случайное целое от a до b RandomReal(a,b) // случайное целое в диапазоне [a,b) Swap(x,y) // Поменять местами значения переменных x и y Min(x1,x2,x3,...) // Минимальное из значений Max(x1,x2,x3,...) // Максиимальное из значений
Стандартная библиотека .NET
[править]
PascalABC.NET имеет непосредственный доступ ко всем классам стандартной библиотеки .NET.
Библиотеки mscorlib.dll и System.Core.dll неявно подключаются к любой программе PascalABC.NET
// Пример 1 ## Print(System.Environment.OSVersion); // или uses System; // Подключение пространства имен .NET uses System.Threading.Tasks; // Подключение пространства имен .NET begin Task.Run(() -> Print(1)); Print(Environment.OSVersion); end. // Пример 2 begin var f := new System.IO.StreamWriter('a.txt'); f.WriteLine('Hello PascalABC.NET!'); f.Close; end. // Пример 3 uses System.Net; begin var w := new WebClient(); Println(w.DownloadString('http://example.com')); end. // Пример 4. Подключение дополнительной стандартной dll {$reference 'System.Windows.Forms.dll'} uses System.Windows.Forms; begin Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); var form := new Form(); Application.Run(form); end.
PascalABC.NET имеет очевидную проекцию своих стандартных типов на типы .NET, что позволяет пользоваться едиными типами в программах, написанных на PascalABC.NET и C#.
| Тип PascalABC.NET | Соответствующий тип .NET |
|---|---|
| integer | System.Int32 |
| longint | System.Int32 |
| int64 | System.Int64 |
| shortint | System.SByte |
| smallint | System.Int16 |
| byte | System.Byte |
| word | System.UInt16 |
| cardinal | System.UInt32 |
| uint64 | System.UInt64 |
| single | System.Single |
| real | System.Double |
| double | System.Double |
| boolean | System.Boolean |
| char | System.Char |
| string | System.String |
| object | System.Object |
// Присваивание a := 5; // Присваивание с распаковкой в переменные (a,b) := (1,2); // из кортежа (a,b) := ReadReal2; // из кортежа, возвращаемого функцией (a,b,c) := (b,c,a); (a[i],a[j]) := (a[j],a[i]); (a,b) := arr; // из массива или другой последовательности // Расширенное присваивание a += 1; a -= 1; a *= 2; x /= 2; // Условный оператор if x mod 2 = 0 then Print(x,'- четное') else Print(x,'- нечетное') // Цепочечные условные операторы if x < 0 then Print('отрицательное') else if x = 0 then Print('Равное 0') else Print('Положительное') // Составной оператор begin .. end if a > b then begin var t := a; a := b; b := t end; // Оператор выбора варианта case word of 'собака': Translation := 'dog'; 'кошка': Translation := 'cat'; 'корова': Translation := 'cow'; else Translation := 'перевод отсутствует'; end; // Оператор выбора варианта с диапазоном и перечислением case Month of 12,1,2: Season := 'Зима'; 3..5: Season := 'Весна'; 6..8: Season := 'Лето'; 9..11: Season := 'Осень'; end; // Цикл loop - повторить n раз loop 10 do Print(1); // Цикл for со счетчиком for var i:=1 to 10 do Print(i); // Цикл for с шагом -1 // 10 9 8 7 6 5 4 3 2 1 for var i:=10 downto 1 do Print(i); // Цикл foreach (для каждого) foreach var x in arr do Print(x); // Цикл foreach с индексом foreach var x in arr index i do Println(i,x); // Цикл for с шагом // 1 3 5 7 9 for var i:=1 to 10 step 2 do Print(i); // Цикл for с отрицательным шагом // 10 8 6 4 2 for var i:=10 to 1 step -2 do Print(i); // Цикл while с предусловием (цикл ПОКА) var x := 1; while x < 10 do begin Print(x); x += 1; end; // Цикл repeat с постусловием (цикл ДО) var x := 1; repeat Print(x); x += 1; until x >= 10; // Оператор break досрочного завершения цикла var sum := 0; repeat var x := ReadInteger; if x = 0 then break; sum += x; until False; // Оператор continue досрочного завершения текущей итерации цикла var sum := 0; loop 10 do begin var x := ReadInteger; if x <= 0 then continue sum += x; end;
// Кортежи var t: (string,integer) := ('Иванов',18); // Доступ к полю кортежа на чтение Println(t.Item1,t.Item2); Println(t[0],t[1]); // Кортежи неизменны. Если надо изменить поле кортежа, то надо конструировать новый кортеж t := (t[0],19); // Распаковка кортежа в переменные var (name,age) := t; // name = 'Иванов', age = 18
// Динамические массивы var a: array of integer; // переменная типа "массив" - ссылка на данные a := new integer[5]; // выделение памяти (заполняется нулями) // Описание массива и выделение памяти var a := new integer[5]; // Описание массива, выделение памяти и заполнение значениями var a := [1,3,5,7,9]; // Автовывод типа массива var a1 := [1,2,3.5]; // array of real var a2 := ['z','t','Hello']; // array of string var a3 := ['z',1]; // ошибка // Возврат памяти, занимаемой массивом a := nil; // Сборка мусора // Вывод массива Print(a); // [1,3,5,7,9] a.Print; // 1 3 5 7 9 // Создающая функция Arr var a := Arr(1..9); // Цикл по индексам массива for var i := 0 to a.Length - 1 do a[i] += 1; // Цикл по элементам массива foreach var x in a do Print(x); // Индексация массивов a[0] // первый элемент a[^1] // первый с конца a[^i] // i-тый с конца // Срезы массивов a := [0,1,2,3,4,5]; a[2:5] // 2 3 4 a[3:] // 3 4 5 a[:3] // 0 1 2 a[:] // копия a[1:^1] // 1 2 3 4 a[::-1] // 5 4 3 2 1 0 a[::2] // 0 2 4 a[1::2] // 1 3 5 // Операция in var a := [1,2,3,5]; Print(4 in a); // False // Операции + и * var a := [1,2,3]; var a1 := [4,5,6]; Print(a + a1); // [1,2,3,4,5,6] Print(a * 2); // [1,2,3,1,2,3] // Сравнение массивов var a := Arr(1,2,3); var a1 := Arr(1,2,3); Print(a = a1); // False - сравниваются ссылки, они - разные Print(a.ArrEqual(a1)); // True - сравниваются значения // Цикл по массиву for var i:=0 to a.Length - 1 do a[i] += 1; foreach var x in a do Print(x); // Статические массивы (устарело) var a: array[1..10] of integer;
// Описание var s: string; // При описании строка инициализируется пустой строкой '' // Индексация s[i] // i-тый символ строки s[^i] // i-тый символ с конца Строки по умолчанию индексируются с 1 (плохая традиция) s[1] - первый символ s[^1] - последний символ В PascalABC.NET имеется директива компиляции, позволяющая строки индексировать с 0: {$zerobasedstrings} s[0] - первый символ s[^1] - последний символ (не меняется!) // Слияние строк var s := 'Hello'; var s1 := 'World'; var s2 := s + ' ' + s1; // Умножение строки на число var s := 'ABC'; var s1 := s * 3; // ABCABCABC // Операция in var s := 'abracadabra'; Print('bra' in s); // True // Сравнение строк var s := 'abc'; var s1 := 'abc'; Print(s = s1); // True - строки сравниваются по значению s := 'abc'; s1 := 'abba'; Print(s < s1); // False - строки сравниваются лексикографически (как в словаре) - мЕньшей является строка, которая первой идёт в словаре // Срезы строк // Настройка {$zerobasedstrings} влияет на индексацию и здесь // Будем рассматривать срезы со включенной опцией {$zerobasedstrings} var s := 'abcdef'; s[1:3] // bc s[:3] // abc s[3:] // def s[1:^1] // bcde s[::-1] // fedcba - инвертирование строки s[::2] // ace s[1::2] // bdf // Циклы по строке for var i:=1 to s.Length do Print(s[i]); {$zerobasedstrings} for var i:=0 to s.Length - 1 do Print(s[i]); foreach var c in s do Print(c); // Преобразования строка - целое var s: string := '456'; var i: integer := 123; s := i.ToString; i := s.ToInteger; // возможно исключение if s.TryToInteger(i) then // безопасное преобразование Print(i); // Преобразования строка - вещественное - аналогично // Основные методы строк // Вставка подстроки. Индексация в методах - с нуля var s := 'Привет, мир!'; s := s.Insert(8, 'прекрасный '); Println(s); // Привет, прекрасный мир! // Удаление подстроки. Индексация в методах - с нуля s := s.Remove(8, 11); // Удаляет 11 символов начиная с 7-й позиции Println(s); // Привет, мир! // Разбиение строки на слова var s := 'Привет, мир! Как дела?'; var words := s.ToWords(AllDelimiters); // Разбиение строки на слова. AllDelimiters - все возможные разделители. По умолчанию - ' ' Println(words); // ['Привет', 'мир', 'Как', 'дела'] // Замена подстроки var s := 'Привет, мир!'; s := s.Replace('мир', 'Паскаль'); Println(s); // Привет, Паскаль!
StringBuilder - эффективно изменяемые строки
[править]
В .NET строки неизменяемы - нельзя в строке поменять символ. Это сделано для эффективности и безопасности в многопоточных приложениях.
Чтобы изменять символы строк, следует использовать тип StringBuilder (эффективно изменяемая строка)
{$zerobasedstrings} var s := 'Table'; // s[0] := 'C'; // Нельзя - строка неизменяема var sb: StringBuilder := s; // Неявное преобразование sb[0] := 'C'; s := sb.ToString;
Тип StringBuilder позволяет также добавлять символы к строке, вставлять в середину строки и удалять
{$zerobasedstrings} var s := 'car'; var sb: StringBuilder := s; sb.Append('d'); // card s := sb.ToString; sb := 'hat'; sb.Insert(1,'e'); // heat s := sb.ToString; Print(sb); sb := 'Planet'; sb.Remove(4,1); // Plant s := sb.ToString;
// Многомерные динамические массивы var a: array[,] of integer := new integer[3,4]; // Создающая функция для двумерного массива (матрицы) var a := Matr([1,2,3,4],[5,6,7,8],[9,10,11,12]); // Вывод двумерного массива a.Print; // Результат 1 2 3 4 5 6 7 8 9 10 11 12 Print(a); // Результат [[1,2,3,4],[5,6,7,8],[9,10,11,12]] // Срезы многомерных массивов a[1:3,2:4] // Результат 7 8 11 12 a[:,1] // одномерный массив - 1 столбец a[2,:] // одномерный массив - 2 строка // Операция in var a := Matr([1,2,3,4],[5,6,7,8],[9,10,11,12]); Print(4 in a); // True // Сравнение матриц var a := Matr([1,2,3,4],[5,6,7,8],[9,10,11,12]); var a1 := Matr([1,2,3,4],[5,6,7,8],[9,10,11,12]); Print(a = a1); // False - сравниваются ссылки Print(a.MatrEqual(a1)); // True - сравниваются элементы Методы матриц (двумерных массивов) var a := Matr([1,2,3,4],[5,6,7,8],[9,10,11,12]); a.RowCount // количество строк a.ColCount // количество столбцов a.Row(i) // i-тая строка матрицы (одномерный массив) a.Col(j) // j-тый столбец матрицы (одномерный массив)
// Создание типа записи type PersonRec = record Name: string; Age: integer; end; // Пременная типа "запись" var p: PersonRec; // Память выделена на программном стеке - конструктор вызывать не надо p.Name := 'Иванов'; p.Age := 18; // Присваивание и сравнение записей var p1: PersonRec; p1.Name := 'Иванов'; p1.Age := 18; Print(p = p1); // True - сравниваются все поля p := p1; // При присваивании копируются все поля // Создание типа класса type Person = class Name: string; Age: integer; end; // Классы - ссылочные данные var p: Person; p := new Person; // Для создания объекта класса требуется вызвать конструктор p.Name := 'Иванов'; p.Age := 18; // Присваивание и сравнение объектов классов var p1: Person; p1.Name := 'Иванов'; p1.Age := 18; Print(p = p1); // False - сравниваются ссылки p := p1; // При присваивании копируется ссылка // Автоклассы - автоматически создают конструктор по полям type Person = auto class Name: string; Age: integer; end; var p := new Person('Иванов',18); // Освобождение памяти, занимаемой объектом p := nil; // память под объект будет возвращена при сборке мусора
Список можно рассматривать как массив с эффективно изменяемым размером
// Описание var L: List<integer>; // Вызов конструктора L := new List<integer>; // Основные методы L.Add(3); // Добавление в конец L.AddRange([1,2,3,4,5]); // Добавление в конец L.Insert(0,666); // Вставка в середину L.RemoveAt(0); // Удаление элемента в заданной позиции L.Count // Количество элементов L.Clear; // Очистка списка // Создающая функция L := Lst(1,2,3,4,5); L := Lst(1..9); // Операция in var L := Lst(2..5); Print(6 in L); // False // Операции + и * var L := Lst(1,2,3); var L1 := Lst(4,5,6); Print(L + L1); // [1,2,3,4,5,6] Print(L * 2); // [1,2,3,1,2,3]
Множество - неупорядоченный набор неповторяющихся значений. В PascalABC.NET имеется несколько типов множеств
Встроенные множества set of T
[править]
var s: set of integer := [1,3,5]; var s1 := SetOf(1,3,5); // создающая функция для множества s1 := s; // копирует содержимое одного множества в другое. Встроенные множества - размерные! s := []; // Пустое множество // Автовывод типа для литералов множеств и массивов var a := [1,2,3,4,5]; // массив var s := [1..3,5]; // множество, т.к. в литерале присутствует диапазон // Элементы во множествах не могут повторяться var s: set of integer := [3,1,5,3,1]; s.Print // Результат: 3 1 5 Print(s); // Результат: {3,1,5} // Основные операции над множествами: s.Count // Количество элементов 3 in s // Принадлежность элемента множеству. Работает за время O(1) s.Add(7); // Добавление элемента к множеству. Работает за время O(1) s.Remove(7); // Удаление элемента из множества. Работает за время O(1) // Другие операции над множествами var s := SetOf(1,2,3); var s1 := SetOf(2,3,4); s * s1 // Пересечение: 2 3 s + s1 // Объединение: 1 2 3 4 s - s1 // Разность: 1 SetOf(1,3) < s // Собственное вложение: True SetOf(1,2,3) <= s // Несобственное вложение: True s = s1 // Множества равны если количества элементов в них равны и все элементы совпадают // Например, если s = SetOf(1,2,3), а s1 = SetOf(3,1,2), то s = s1 s <> s1 s > s1 s >= s1 // В других операциях с множествами один из операндов может быть массивом: [1,3] < s s = [1,3,2]
// Описание переменной var s := new HashSet<integer>; // пока множество пустое s := [1,2,3]; // множество заполняется значениями 1, 2, 3 s := HSet(1,2,3); // Создающая функция для HashSet // или описание с инициализацией var s: HashSet<integer> := [1,2,3]; // или с автовыводом типа var s := HSet(1,2,3); // Добавление значений s.Add(5); // Печать s.Print; // 1 2 3 5 Print(s); // {1,2,3,5} // Все методы и операции, приведенные для set of T, работают и для HashSet // В частности сравнение на равенство сравнивает все элементы независимо от порядка var s := HSet(1,2,3); Print(s = HSet(2,3,1)); // True // Важное отличие HashSet от встроенных множеств: HashSet - ссылочный тип. То есть var s1 := HSet(4,5,6); s := s1; // присваиваются ссылки
Словарь - неупорядоченный набор пар вида (ключ,значение) с быстрым поиском по ключу
// Описание словаря var d: Dictionary<string,integer>; // переменная типа "словарь" d := new Dictionary<string,integer>; // вызов конструктора словаря // Описание словаря и выделение памяти var d := new Dictionary<string,integer>; // Создающая функция для словаря - Dict // Создающая операция для пары (ключ,значение) - ключ to значение var d := Dict('бегемот' to 2, 'крокодил' to 3); var d1 := Dict(d); // копия словаря var d2 := Dict(['бегемот','какаду'],[3,5]); // создание словаря заданием массивов ключей и значений // Операции d.Update(d1); // обновляет данные словаря d данными словаря d1 'бегемот' in d; // есть ли пара со значением ключа 'бегемот' d.Contains('бегемот'); // синоним 'бегемот' in d d += d1; // синоним d.Update(d1) d + d1 // Слияние словарей. Данные d1 приоритетны d -= [ключи] // Исключает пары, в которых ключи - из последовательности справа d - [ключи] // возвращает новый словарь с исключенными из первого словаря парами с указанными значениями ключа // Возврат памяти, занимаемой словарем d := nil; // Сборка мусора // Вывод словаря Print(d); // {(бегемот,2),(крокодил,3)} d.Print; // (бегемот,2) (крокодил,3) // Цикл по словарю // kv - переменная типа KeyValuePair<ключ, значение> со свойствами Key и Value foreach var kv in d do Println(kv.Key, kv.Value); // Цикл по ключам словаря foreach var k in d.Keys do Println(k, d[k]);
var st := new Stack<Integer>; // Описание, вызов конструктора // Операции со стеком st.Push(10); // Добавление элемента на вершину стека var removedItem := st.Pop(); // Удаление элемента с вершины и сохранение его в removedItem var topItem := st.Peek(); // Получение элемента на вершине без его удаления var count := st.Count; // Получение количества элементов в стеке var isEmpty := st.IsEmpty; // Проверка, пуст ли стек
var q := new Queue<Integer>; // Описание, вызов конструктора // Операции с очередью q.Enqueue(10); // Добавление элемента в конец очереди var removedItem := q.Dequeue(); // Удаление элемента из начала очереди и сохранение его в removedItem var frontItem := q.Peek(); // Получение элемента в начале очереди без его удаления var count := q.Count; // Получение количества элементов в очереди var isEmpty := q.IsEmpty; // Проверка, пуста ли очередь
// Процедура с параметрами procedure PrintPerson(name: string; age: integer); begin Println($'Имя: {name} Возраст: {age}'); end; // Короткий синтаксис процедур procedure PrintPerson(name: string; age: integer) := Println($'Имя: {name} Возраст: {age}'); // Функция function Add(a,b: real): real; begin Result := a + b; end; // Короткий синтаксис функций function Add(a,b: real): real := a + b; // передача параметров по ссылке - выходные параметры procedure CalcSumProd(a,b: real; var sum,prod: real); begin sum := a + b; prod := a * b; end; // Функция, возвращающая кортеж function SumProd(a,b: real): (real,real) := (a + b, a * b); ... var (s,p) := SumProd(2,3); // Переменное количество параметров function SumSquares(params a: array of real): real; begin Result := 0; foreach var x in a do Result += x * x; end; SumSquares(1, 2, 3).Print; // Выведет 14 // Параметры по умолчанию procedure Greet(name: string := 'Guest'); begin Println($'Hello, {name}!'); end; Greet(); // Выведет 'Hello, Guest!' Greet('Alice'); // Выведет 'Hello, Alice!' procedure ShowInfo(name: string := 'Guest'; age: integer := 18); begin Println($'Name: {name}, Age: {age}'); end; // Вызов с использованием именованных аргументов: ShowInfo(age := 25); // Выведет: Name: Guest, Age: 25 ShowInfo(name := 'Alice'); // Выведет: Name: Alice, Age: 18 ShowInfo(age := 30, name := 'Bob'); // Можно в любом порядке // Обобщенные параметры procedure RotateRight<T>(arr: array of T); begin var n := arr.Length; var last := arr[^1]; for var i := n - 1 downto 1 do arr[i] := arr[i - 1]; arr[0] := last; end; // Передача записей по ссылке на const type Person = record Name: string; Age: integer; end; procedure PrintPerson(const p: Person); begin Print(p.Name,p.Age); // запись p внутри процедуры менять нельзя end;
Переменная, которая хранит ссылку на функцию, называется функциональной переменной (или процедурной переменной если хранит ссылку на процедуру). Функциональной переменной можно присвоить функцию с соответствующими параметрами и возвращаемым значением. Затем функциональную переменную можно использовать для вызова функции.
// Пример функции и соответствующей функциональной переменной function f(x: real): real := x * x; // Тип функциональной переменной: real -> real var ff: real -> real := f; ff(5).Print; // вызов функции через функциональную переменную // Пример 2 function Mult(x,y: real): real := x * y; var ff2: (real,real) -> real := Mult; ff2(5,6).Print; // вызов функции через функциональную переменную // Типы функциональных переменных real -> real (integer,integer) -> boolean (string,integer) -> () // процедура с двумя параметрами () -> () // процедура без параметров procedure // синоним () -> () // Функциональные типы с развернутым описанием type Proc = procedure(x,y: real; var a,b: real); Fun<T> = function(lst: List<T>; a,b: T): List<T>;
Функции могут быть переданы как параметры в другие функции и затем могут быть вызваны. Такой вызов называется Callback (обратный вызов), а сама функция - функцией обратного вызова.
// Описание функции с функциональным параметром condition function Filter(lst: List<integer>; condition: integer -> boolean): List<integer>; begin Result := new List<integer>; foreach var x in lst do if condition(x) then // обратный вызов Result.Add(x); end; // Функция, используемая в качестве функционального параметра function Even(x: integer) := x mod 2 = 0; // Вызов var L := Lst(1..10); Filter(L, Even).Print; // 2 4 6 8 10
Лямбда-выражение - это анонимная (безымянная) функция, которая определяется в месте своего использования. Лямбда-выражения можно присваивать функциональным переменным и передавать в другие функции как callback.
// Общая форма лямбда-выражения параметры -> значение // для лямбда-функций параметры -> действие // для лямбда-процедур // Инициализация функциональной переменной лямбда-выражением // Типы параметров лямбда-функции и тип возвращаемого значения автовыводятся из типа функциональной переменной var f: real -> real := x -> x*x; var pred: (real,real) -> boolean := (x,y) -> x < y; var pr: integer -> () := n -> Print(n); var hello: procedure := procedure -> Print('Hello'); // Вызов через функциональную переменную f(5).Print; pred(3,2).Print; pr(77); hello; // Передача лямбда-выражения как параметра функции var a := Arr(1..10); a.Select(x -> x * x).Println; // лямбда-преобразование a.Where(x -> x mod 2 = 0).Println; // лямбда-условие
Последовательность – это набор элементов, которые можно перебирать один за другим. Для перебора обычно используют цикл foreach или методы последовательностей.
У большинства последовательностей элементы не хранятся одновременно в памяти, а вычисляются по мере необходимости. В то же время, существуют разновидности последовательностей, называемые коллекциями, у которых все элементы хранятся в памяти одновременно. К таким последовательностям относятся, например, массивы, списки и множества.
Описание и стандартные генераторы
[править]
// Описание последовательности var s: sequence of integer; // Инициализация последовательности конкретными значениями s := Seq(1,4,8); // Инициализация последовательности элементами от 1 до 10 s := Range(1,10); // Инициализация последовательности элементами от 1 до 10 с шагом 2 s := Range(1,10,2); // 1 3 5 7 9 // Инициализация последовательности с отрицательным шагом s := Range(10,1,-2); // 10 8 6 4 2 // Генератор вещественной последовательности с шагом var sr: sequence of real; sr := Range(1,3,0.2); // 1 1.2 1.4 1.6 1.8 2 2.2 2.4 2.6 2.8 3 // Генератор вещественной последовательности на основе отрезка, разбитого на n частей var sr: sequence of real; sr := PartitionPoints(1,3,10); // 1 1.2 1.4 1.6 1.8 2 2.2 2.4 2.6 2.8 3 // Цикл по последовательности foreach var x in s do Print(x); // Распаковка последовательности в переменные var s := Range(1,3,0.2); var (a,b) := s; // a = 1, b = 1.2
Методы последовательностей
[править]
// Основные операции с числовыми последовательностями s.Sum // Сумма элементов s.Average // Среднее значение s.Min // Минимум s.Max // Максимум // Первый, последний, количество s.Count s.First s.Last // Числовые характеристики s.CountOf(3) // Количество троек s.Count(x -> x in 2..5) // Количество элементов в диапазоне 2..5 // Печать элементов через пробел s.Print s.Println // Печать элементов - каждый на новой строке s.PrintLines // Выбор и пропуск элементов s.Take(n) // возвращает последовательность из n первых элементов s.Skip(n) // пропускает n первых элементов и возвращает оставшуюся последовательность s.TakeWhile(x -> x > 5) // Возвращает начальные элементы последовательности, большие 5 s.SkipWhile(x -> x > 5) // Пропускает начальные элементы последовательности, большие 5 s.TakeLast(n) // Возвращает последовательность n последних элементов s.SkipLast(n) // Возвращает последовательность без n последних элементов // Условия для последовательностей s.All(x -> x > 3) // Все больше 3? s.Any(x -> x > 3) // Есть ли элемент больше 3? s.Contains(3) // Содержит 3? s.SequenceEqual(s1) // Равны ли последовательности // Преобразование в другие структуры s.ToArray // В массив s.ToList // В список s.ToSet // В set of T s.ToHashSet // В HashSet // Преобразование последовательности в последовательность s.Where(x -> x > 3) // возвращает последовательность элементов больше 3 s.Select(x -> x * x) // возвращает последовательность квадратов элементов s.Order // возвращает последовательность, отсортированную по возрастанию s.OrderDescending // возвращает последовательность, отсортированную по убыванию s.Distinct // возвращает последовательность неповторяющихся элементов s.Reverse // возвращает инвертированную последовательность // Две и более последовательностей var s := Seq(1,2,3); var s1 := Seq(4,5,6); s.Zip(s1) // объединяет две последовательности в последовательность кортежей: (1,4) (2,5) (3,6) s.Zip(s1, (x,y) -> x * y) // объединяет две последовательности по заданному правилу: 4 10 18 Zip(s,s1,s,(x,y,z) -> x + y + z) // Внешняя Zip s.Concat(s1) // слияние последовательностей: 1 2 3 4 5 6 s.Cartesian(s1) // декартово произведение последовательностей: (1,4) (1,5) (1,6) (2,4) (2,5) (2,6) (3,4) (3,5) (3,6) s.Interleave(s1) // Чередует элементы двух последовательностей: 1 4 2 5 3 6 // Перестановки и сочетания var s := 'abc'; // Строка - это последовательность символов s.Permutations.Print; // Все перестановки: abc acb bac bca cab cba s := 'abcd'; s.Permutations(2).Print; // Все частичные перестановки длины 2: ab ba ac ca ad da bc cb bd db cd dc s.Combinations(2).Print; // Все сочетания по 2 элемента: ab ac ad bc bd cd // Выполнение операции для всех элементов var s := Seq(1,2,3,4); s.ForEach(x -> Print(x)); // Печать каждого элемента // Превращение в составную последовательность var s := Seq(55,23,14,76,93,48); s.Numerate.Println; // Нумерует элементы последовательности, возвращая кортежи (номер, элемент) // Вывод: (1,55) (2,23) (3,14) (4,76) (5,93) (6,48) s.Pairwise.Println; // возвращает последовательность кортежей пар соседних элементов // Вывод: (55,23) (23,14) (14,76) (76,93) (93,48) s.NWise(3).Println; // Превращает последовательность в последовательность массивов, содержащих n соседних элементов (n=3) // Вывод: [55,23,14] [23,14,76] [14,76,93] [76,93,48] s.Batch(3).Println; // разбивает последовательность на серии длины 3 (массивы) // Вывод: [55,23,14] [76,93,48] // Flatten - преобразование последовательности последовательностей в плоскую последовательность var aa := [[1,2,3,4],[5,6,7,8],[9,10,11,12]]; aa.Flatten.Print; // Flatten сливает внутренние последовательности в одну плоскую: 1 2 3 4 5 6 7 8 9 10 11 12 // Метод SelectMany // Метод SelectMany используется для проекции каждого элемента последовательности // в другую последовательность и затем объединяет все эти последовательности в одну var listOfStrings := ['Hello world', 'Pascal is great', 'LINQ in action']; listOfStrings.SelectMany(x -> x.ToWords).Print; // Hello world Pascal is great LINQ in action // Группировка var s := Seq(1,2,3,4,5,6,7,8,9); s.GroupBy(x -> x mod 3).Print; // Разбиение на последовательность групп с одинаковым остатком при делении на 3 // Вывод: [1,4,7] [2,5,8] [3,6,9] // Количество каждого элемента var s := Seq(1,2,1,1,2,3); s.EachCount.Print; // возвращает словарь пар (элемент,количество): (1,3) (2,2) (3,1) // Диапазоны как последовательности (1..9).Println // 1 2 3 4 5 6 7 8 9 // Сортировка по разным критериям var words := ['cat', 'bread', 'chair', 'door', 'dog', 'school', 'yellow', 'apple', 'table', 'flower']; words.OrderBy(word -> word.Length).ThenBy(word -> word).Println; // упорядочить вначале по длине, а при равной длине по алфавиту // cat dog door apple bread chair table flower school yellow // Числовые характеристики для нечисловых последовательностей words.Sum(word -> word.Length).Print; // Суммарная длина слов words.Average(word -> word.Length).Print; // Средняя длина слов words.Max(word -> word.Length).Print; // Максимальная длина слова words.Min(word -> word.Length).Print; // Минимальная длина слова // Цепочки методов. Методы можно объединять в цепочки var a := Arr(9,7,2,1,8,5,6,7,1); // Отфильтровать нечетные, убрать дубли, возвести в квадрат, отсортировать a.Where(x -> x mod 2 <> 0).Println.Distinct.Println.Select(x -> x * x).Println.Order.Println; // Вывод 9 7 1 5 7 1 9 7 1 5 81 49 1 25 1 25 49 81 // Вывод последовательности в файл s.WriteLines(filename)
Пользовательские генераторы последовательностей
[править]
Генератор последовательностей в PascalABC.NET — это функция, которая возвращает элементы последовательности по одному, используя оператор yield. Генераторы позволяют создавать ленивые последовательности, где элементы вычисляются только по мере необходимости.
Оператор yield используется внутри генератора для возврата текущего элемента последовательности и приостановки выполнения функции до следующего запроса элемента. Выполнение продолжается с того места, где было остановлено.
// Функция - генератор последовательности function GenerateEvenNumbers(n: integer): sequence of integer; begin for var i := 0 to n do if i mod 2 = 0 then yield i; end; // Использование в цикле foreach foreach var x in GenerateEvenNumbers(10) do Print(x); // Вывод: 0 2 4 6 8 10 // Использование методов последовательностей GenerateEvenNumbers(10).Println;
Оператор yield sequence используется внутри генератора для возврата подпоследовательности
function GenerateEvenNumbers(n: integer): sequence of integer; begin for var i := 0 to n do if i mod 2 = 0 then yield i; end; function GenerateOddNumbers(n: integer): sequence of integer; begin for var i := 0 to n do if i mod 2 <> 0 then yield i; end; // Функция с yield sequence function GenerateSeq(n: integer): sequence of integer; begin yield sequence GenerateEvenNumbers(n); yield 777; yield sequence GenerateOddNumbers(n); end; // Использование GenerateSeq(10).Println; // 0 2 4 6 8 10 777 1 3 5 7 9
Модули — это основные единицы компиляции, предназначенные для структурирования и логического разделения большой программы на части.
Модуль должен храниться в файле с тем же именем, что и имя модуля: MyUnit.pas
unit MyUnit; interface // Раздел интерфейса: видимые извне объявления type int = integer; // Сокращение для типа integer double = real; // Сокращение для типа real function SumSquares(a, b: int): int; // Объявление функции implementation // Раздел реализации: детали, скрытые от внешнего кода function SumSquares(a, b: int): int := a * a + b * b; // Реализация функции end.
Упрощенная структура модуля
[править]
unit MyUnit; // Нет деления на интерфейс и реализацию. Удобно для небольших модулей type int = integer; double = real; function SumSquares(a, b: int): int := a * a + b * b; end.
uses MyUnit; begin var a: int := 1; var b: int := 2; Print(SumSquares(a,b)); end.
Подключение пространств имен .NET
[править]
// Пространства имен .NET имеют тот же синтаксис подключения, что и модули uses System.Net; uses System.Text; begin var w := new WebClient(); w.Encoding := Encoding.UTF8; var s := w.DownloadString('http://pascalabc.net'); Println(s); end.
Библиотеки — это другой способ организации кода большой программы. Библиотеки содержат связанные классы и функции в одном файле, который компилируется в файл с расширением .dll, называемый сборкой.
Сборки можно затем подключать к программам, написанным на любом .NET-языке (в частности, к программам на C#)
Как и модуль, библиотека должна храниться в файле с тем же именем, что и имя библиотеки: MyLib.pas
library MyLib; type int = integer; // Сокращение для типа integer double = real; // Сокращение для типа real function SumSquares(a, b: int): int := a * a + b * b; end.
Сборки (откомпилированные библиотеки) подключаются к Pascal-программе при помощи специальной директивы компилятора {$reference MyLib.dll}
{$reference MyLib.dll} begin var a: int := 3; var b: int := 4; SumSquares(a,b).Print; end.
Сборка может быть написана и откомпилирована на любом .NET - языке.
Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на представлении программы в виде набора объектов, которые взаимодействуют друг с другом. Каждый объект является экземпляром класса и объединяет данные (состояние) и методы (поведение), которые могут работать с этими данными.
type Point = class private // видимость только для членов класса и внутри модуля, где определен класс x,y: real; public // Конструктор - метод, создающий объект класса constructor Create(x,y: real); // Конструктор всегда имеет имя Create. Можно писать constructor (x,y: real); begin Self.x := x; // Self - ссылка на себя Self.y := y; end; procedure Print; // Метод класса begin PABCSystem.Print($'({x},{y})'); // PABCSystem - стандартный модуль end; // Статический метод - вызывается через имя типа static function RandomPoint: Point; begin Result := new Point(Random(800),Random(600)); end; end; begin var p := new Point(2,3); // Вызов конструктора // Ссылочная объектная модель: переменная типа "класс" - это ссылка на объект, создаваемый конструктором p.Print; // (2,3) Point.RandomPoint.Print; // (603,176) end.
// В автоклассах автоматически по полям генерируется конструктор и представление для вывода type Point = auto class x,y: real; end; begin var p := new Point(2,3); Print(p); // (2,3) end.
Свойства классов - это "умные поля". При доступе к ним на чтение и запись выполняются дополнительные действия.
Обычно свойства используются
- либо когда надо сделать доступ только на чтение
- либо когда при доступе на запись надо проверить диапазон значений
type Person = class private fname: string; fage: integer; procedure SetAge(age: integer); // Логика доступа на запись begin if age < 0 then raise new System.ArgumentOutOfRangeException('Параметр должен быть >= 0'); fage := age; end; public property Name: string read fname; // Name - только на чтение property Age: integer read fage write SetAge; end; begin var p := new Person('Ivsnov',20); //p.Name := 'Petrov'; // Ошибка - нет метода для записи p.Age := -1; // Исключение: Параметр должен быть >= 0 end.
Любой тип, в том числе стандартный, можно расширить новыми методами.
Метод расширения описывается как обычная функция с модификатором extensionmethod. Первый параметр должен иметь имя Self и тип, который мы хотим расширить данным методом.
function MultBy2(Self: integer): integer; extensionmethod; begin Result := Self * 2; end; begin var i: integer:= 3; i.MultBy2().Print end.
type Pair<T1, T2> = class public auto property First: T1; // автосвойство создает внутреннее поле и методы на чтение и запись auto property Second: T2; constructor Create(f: T1; s: T2); begin First := f; Second := s; end; end; begin var p := new Pair<integer, string>(1, 'Hello'); Println($'{p.First}, {p.Second}'); // 1, Hello end.
Класс можно унаследовать от другого класса - наследуются все поля, свойства и методы
type Figure = class public procedure PrintType := Println('Тип фигуры: ', TypeName(Self)); end; // Определение производного класса Circle Circle = auto class(Figure) public x, y, radius: real; function Area: real := Pi * radius * radius; end; // Определение производного класса Rectangle Rectangle = auto class(Figure) public x, y: real; width, height: real; function Area: real := width * height; end; begin var c := new Circle(0, 0, 5); c.PrintType; // Вывод: Тип фигуры: Circle Println('Площадь окружности: ', c.Area); // Вывод: Площадь окружности: 78.54 var r := new Rectangle(1, 1, 4, 6); r.PrintType; // Вывод: Тип фигуры: Rectangle Println('Площадь прямоугольника: ', r.Area); // Вывод: Площадь прямоугольника: 24 end.
Полиморфизм - способность объектов разных типов, связанных иерархией наследования, реализовывать одни и те же действия по разному (полиморфизм - много форм). Полиморфизм реализуется через виртуальные функции
type Animal = class procedure Speak; virtual := Println(''); end; Dog = class(Animal) procedure Speak; override := Println('Gaw gaw!'); // в производных классах - override end; Cat = class(Animal) procedure Speak; override := Println('Mia-ay!'); end; begin var a: Animal := new Dog; a.Speak; // Gaw gaw! a := new Cat; a.Speak; // Mia-ay! end.
Интерфейс – набор требований, которым должен удовлетворять класс. В интерфейсе содержатся заголовки методов и свойств.
// Определение интерфейса type IAnimal = interface procedure Speak; function GetName: string; end; // Классы, реализующие интерфейсы Dog = class(IAnimal) public // обязательно публичным образом function GetName: string := 'Dog'; procedure Speak := Println('Woof'); end; Cat = class(IAnimal) public function GetName: string := 'Cat'; procedure Speak := Println('Meow'); end; // Использование интерфейсов procedure MakeSound(animal: IAnimal); begin Println('Animal: ' + animal.GetName); animal.Speak; end; begin var d: IAnimal := new Dog; var c: IAnimal := new Cat; MakeSound(d); MakeSound(c); end.
Ограничения на параметры обобщений
[править]
В обобщенных классах и функциях можно накладывать ограничения на параметры обобщений в секции where.
// Общий пример function DoSomething<T>: T; where T: class, constructor, IComparable<T>; begin // ... end; // Виды ограничений: where T: class; // тип должен быть ссылочным where T: record; // тип должен быть размерным where T: constructor; // тип должен иметь конструктор по умолчанию where T: IComparable<T> // тип должен реализовывать интерфейс where T: Person; // тип должен наследоваться от определенного базового класса // Пример function Min<T>(a: array of T): T; where T: IComparable<T>; begin Result := a[0]; for var i:=1 to a.Length - 1 do if a[i].CompareTo(Result) < 0 then Result := a[i]; end;
Все исключения наследуются от общего класса System.Exception.
// Обработка исключений в блоке try/except try var i := ReadInteger; // Неверный ввод вызовет исключение var x := 10 div i; // Деление на ноль вызовет исключение except on e: System.DivideByZeroException do Println('Ошибка: ', e.Message); on e: System.FormatException do Println('Ошибка: ', e.Message); end; // Блок try..finally procedure p; begin var f := OpenRead('a.txt'); try var i := f.ReadInteger; finally f.Close; // файл закрывается независимо от того, произошло исключение или нет end; end;
Идентификация типов во время выполнения -
[править]
// Операции as, is type Person = auto class Name: string; end; Student = class(Person) Group: string; constructor Create(name, group: string); begin inherited Create(name); Self.Group := group; end; end; begin var p: Person := new Student('Alice', 'CS-101'); if p is Student then // Является ли объект p экземпляром класса Student Student(p).Group := 'CS-102'; // Приводим объект p к типу Student и изменяем его группу var s := p as Student; // Приводим объект p к типу Student if s <> nil then // Если приведение успешно, изменяем группу s.Group := 'CS-102'; // Используем расширенную форму is // Если p это Student, то s1 - переменная типа Student if p is Student (var s1) then s1.Group := 'CS-102'; end. // Метод GetType Метод GetType позволяет получить информацию о типе объекта во время выполнения программы: var p: Person := new Student('Alice', 'CS-101'); if p.GetType = typeof(Student) then Student(p).Group := 'CS-102';
// Типы, допускающие значение nil var i: integer?; // i может принимать все целые значения и nil i := nil; i := 10; if i = nil then Print('Nullable'); if i = 10 then i := i.Value + 5; // Операция ?. var a: array of integer; Print(a?.Length); // nil вместо исключения a := new integer[3]; Print(a?.Length); // 3 // Операция ?? // x ?? y - возвращает x, а если x возвращает nil, то возвращает y var a: array of integer; Print(a?.Length ?? 0); // 0 a := new integer[3]; Print(a?.Length); // 3