Редактировать

Описания переменных внутри блока и автовывод типов

В большинстве случаев переменные описываются в блоке begin-end и описание совмещается с инициализацией:

begin
  var a := 5;
  var r := 3.14;
  var s := 'ABC';
end.

Это решает сразу несколько проблем:

  • можно не говорить о типах в первых программах или лишь упоминать их
  • невозможно забыть инициализировать переменную
  • переменные описываются по мере необходимости близко к месту их использования. Это улучшает читаемость. Проблема старого Паскаля, когда груда переменных описывалась до beginа, отсутствует

При таком способе возникает одна проблема: если надо накопить сумму вещественных, то такой код приведет к ошибке типов:

begin
  var sum := 0;
  loop 10 do
    sum += ReadReal;
end.

Для исправления этой ошибки всё равно придётся говорить о типах и инициализировать sum одним из двух способов:

var sum := 0.0;

или

var sum : real := 0;

Цикл for var

Переменная - счётчик цикла for всегда должна описываться в заголовке цикла:

for var i:=1 to 9 do
  Print(i);
for var i:=21 to 29 do
  Print(i);

Это делает невозможным использование счётчика цикла вне цикла

Цикл loop

Если количество повторений цикла заранее известно, но неважен номер повторения, то используется цикл loop:

loop 9 do
  Write('*');

Множественное описание переменных с инициализацией

Можно инициализировать сразу несколько переменных в момент описания:

var (a,b) := (1,2);
var (Имя,Возраст) := ('Иванов',15);

Вывод

Для вывода вместо процедуры Write предпочтительно использовать процедуру Print. В отличие от Write она разделяет элементы вывода пробелами. Например:

begin
  var (a,b,c) := (1,2,3);
  Println(a,b,c);
  for var i:=1 to 9 do
    Print(i);
end.

Для вывода нескольких значений с пояснениями рекомендуется использовать интерполированные строки:

begin
  var (a,b) := ReadInteger2;
  Println($'Сумма {a} и {b} равна {a + b}');
end.

вместо режущего глаз

Writeln('Сумма ', a ' и ', b, ' равна ', a + b);

Ввод

Ввод принято осуществлять, используя функции вида ReadInteger, ReadReal и т.д.:

begin
  var a := ReadInteger;
end.

Это позволяет совмещать описание переменной с инициализацией и автовыводом типа. В качестве дополнительных бонусов: можно делать приглашение к вводу как параметр функции ввода и вводить сразу несколько переменных одного типа:

begin
  var a := ReadReal('Введите a: ');
  var (m,n,p) := ReadInteger3;
  var (x,y) := ReadReal2('Введите координаты точки: ');
end.

Для ввода с контролем ошибок используется функция TryRead. Она возвращает False если ввод осуществлён неверно (введено не число или число выходит за границы диапазона). Типичный пример её использования:

begin
  var i: integer;
  while not TryRead(i,'Введите i:') do
    Println('Повторите ввод!');
end.

Тип BigInteger

Для работы с длинными целыми используется тип BigInteger. Например, чтобы вычислить 100!, достаточно написать следующий код:

begin
  var p: BigInteger := 1;
  for var i := 2 to 100 do
    p *= i;
  Println(p);  
end.

Константу BigInteger можно также создать, используя суффикс bi - тогда предыдущий код изменится следующим образом:

begin
  var p := 1bi;
  for var i := 2 to 100 do
    p *= i;
  Println(p);  
end.

Некоторые полезные стандартные процедуры, функции и операции

Для обмена значений двух переменных a и b используйте стандартную функцию Swap(a,b):

begin
  var (a,b) := ReadReal2;
  Println(a,b);
  Swap(a,b);
  Println(a,b);
end.

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

begin
  var a,b := ReadReal2;
  Println(a,b);
  var t := a;
  a := b;
  b := t;
  Println(a,b);
end.

Но далее следует использовать Swap.

Минимальное и максимальное среди множества значений можно вычислить, используя стандартные функции Min и Max:

begin
  var a,b,c,d := ReadReal4;
  Println(Min(a,b),Max(c,d));
  Println(Min(a,b,c,d)); // произвольное количество значений
end.

Для возведения в степень используется операция **:

begin
  Println(2 ** 10);
  Println(2 ** 0.5);
end.

Возведение в целую степень оптимизировано и работает быстрее стандартной функции Power(a,n).

Для проверки принадлежности диапазону используется конструкция x in a..b:

begin
  var x := ReadInteger;
  if x in 10..99 then
    Print('Двузначное число');
end.

Эта операция эффективна и переводится в

begin
  var x := ReadInteger;
  if (x >= 10) and (x <= 99) then
    Print('Двузначное число');
end.

Диапазоны также можно использовать для вещественных значений и для символов:

r in 2.5..3.8
c in 'a'..'z'

Для проверки принадлежности множеству значений используется либо множество:

x in [2,3,5,7,11]

либо массив:

x in |2,3,5,7,11|

Мы рекомендуем второй способ - он существенно более эффективен по скорости и по памяти.

Условная операция

Если переменной необходимо присвоить значение в зависимости от условия, то вместо условного оператора иногда нагляднее использовать условную операцию:

begin
  var (a,b) := ReadInteger2;
  var min := if a<b then a else b;
  Print(min);
end.

Методы в стандартных типах

В PascalABC.NET внутри каждого типа имеется ряд полезных методов. В отличие от внешних процедур и функций, они “вшиты” в тип - переменная знает все свои методы и может вызывать их, используя точечную нотацию.

Например, чтобы вывести значение переменной базового типа, можно использовать метод Print:

begin
  var i: integer := 5;
  i.Print;
end.

Из других интересных методов для начинающих для целых типов отметим:

i.IsEven - является ли i чётным
i.IsOdd - является ли i нечётным
i.InRange(a,b) - находится ли значение i между a и b (включительно)
i.Sqrt - квадратный корень

Например, в следующей программе вычисляется количество четных двузначных из 10 введённых:

begin
  var count := 0;
  loop 10 do
  begin
    var x := ReadInteger;
    if i.IsEven and i.InRange(10,99) then // не требует написания скобок
      count += 1;
  end;
  count.Print
end.

Для вещественных значений полезными являются методы

r.Sqrt
r.Round
r.Trunc
r.InRange(a,b) - находится ли значение r между a и b (включительно)

В частности, удобно использовать цепочечную точечную нотацию:

begin
  var x := 17;
  var IsPrime := True;
  for var i:=2 to x.Sqrt.Round do
    if x mod i = 0 then
    begin
      IsPrime := False;
      break
    end;
  IsPrime.Print;
end.

Для всех числовых типов также определены константы MinValue и MaxValue. Чтобы обратиться к ним, следует использовать имя типа:

integer.MinValue
real.MaxValue

Кортежи

Кортежи представляют собой способ объединить несколько значений в одно целое. Значения типа Кортеж записываются в круглых скобках: (1,2,3) или ('Иванов',15). с помощью кортежей можно выполнять одновременные присваивания нескольким переменным:

begin
  var a,b: integer;
  (a,b) := (3,5);
  (a,b) := (b,a);
end.

Присваивание (a,b) := (b,a) позволяет поменять значения двух переменных.

Использование кортежей даже в начальных задачах крайне многообразно.

Пример 1. Нахождение наибольшего общего делителя

begin
  var (a,b) := ReadInteger2; 
  while b>0 do
    (a,b) := (b, a mod b);
  Print('НОД = ', a); 
end.

Пример 2. Числа Фибоначчи

begin
  var (a,b) := (1,1); 
  loop 20 do
  begin
    Print(a); 
    (a,b) := (b, a + b);
  end;
end.