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

Материал из Deeptown Manual
Перейти к: навигация, поиск
(WUCheWUIOMugUtgL)
 
(не показана 1 промежуточная версия 1 участника)
Строка 1: Строка 1:
G6U30h , [url=http://lypqlevvbgle.com/]lypqlevvbgle[/url], [link=http://meovscicmutg.com/]meovscicmutg[/link], http://ghdormjhxgjd.com/
+
Про объявление как переменных так и констант уже достаточно много говорилось в предыдущих главах этой книги. Вероятно, Читатель уже хорошо себе представляет что такое [[переменные]], чем они отличаются от [[Константы|констант]] и как следует их [[Переменные#Типизация при инициализации|инициализировать]]. Читатель уже должен представлять себе, что такое [[Переменные#Понятие переменной, тип переменной|тип]] переменной или константы, и чем статически типированные переменные отличаются от нетипированных, [[Переменные#Нетипированные (динамические) переменные|динамических переменных]]. В этой главе мы не будем уделять много внимания философским вопросам, касающимся переменных и констант, а опишем только сами синтаксические конструкции объявления.
 +
 
 +
Вот несколько примеров объявления как одиночной переменной, так и группы переменных в рамках одного оператора:
 +
 
 +
<source lang="kpp" line="1">
 +
var x;
 +
var x = "hello";
 +
var x, y;
 +
var x, y = 0;
 +
var int x, y;
 +
var int x, real y;
 +
var int x = "1", y = 1.5;
 +
</source>
 +
 
 +
При объявлении переменных важно понимать, что при явном указании типа переменной, он сопостовляется только идентификатору идущему сразу после него. Таким образом, строка 5 объявляет переменную ''x'' типа <tt>[[Стандартные типы данных#Целые числа|int]]</tt>, в то время как переменная ''y'' будет иметь [[Переменные#Нетипированные (динамические) переменные|динамический тип]].
 +
 
 +
То же самое относится и к инициализаторам, которые ставятся в соответствие только той переменной, которая стоит слева от оператора "=". К примеру, выражение в строке 4 будет инициализировать только переменную ''y'', в то время как переменная ''x'' не будет иметь инициализатора; то есть для переменной ''x'' объявление эквивалентно тому что записано в строке 1.
 +
 
 +
Обратите внимание на строку 7: переменная ''x'' имеет инициализатор типа <tt>string</tt>, но ввиду того что тип переменной указан явным образом, переменная будет иметь тип <tt>int</tt>. При этом, тип инициализатора будет ''приведен'' к типу переменной. Если же типы переменной и инициализатора ''неприводимы'', — будет выдано сообщение об ошибке.
 +
 
 +
Приведем еще раз те же самые примеры, но оформим их в виде таблицы, дополнив сведениями о типах переменых:
 +
 
 +
<source lang="kpp">
 +
//Строка объявления        Тип x    Тип y      Инициализатор x  Инициализатор y
 +
 
 +
var x;                    динамика 
 +
var x = "hello";            string                  "hello" 
 +
var x, y;                  динамика  динамика
 +
var x, y = 0;              динамика    int                              0
 +
var int x, y;                int    динамика
 +
var int x, real y;          int      real
 +
var int x = "1", y = 1.5;    int      real        "1" as int        1.5
 +
</source>
 +
 
 +
'''Примечание:''' как видно из таблицы, существует различие между инициализацией переменной и присваиванием ей значения, которое заключается в том, что в зависимости от условий, тип переменной может оказаться либо динамическим, либо фиксированным статическим; внешне же, выражения вызывающие такое поведение, могут выглядеть очень похоже. Рассмотрим следующий пример:
 +
 
 +
<source lang="kpp">
 +
var x = 0;
 +
var y;
 +
y = 0;
 +
</source>
 +
 
 +
В результате выполнения этого кода и переменная ''x'', и переменная ''y'' будут иметь значение равное 0. Более того, типы переменных в этот момент будут совпадать и равны <tt>int</tt>. Однако, переменная ''x'' будет иметь статический тип, в то время как переменная ''y'' — [[Переменные#Нетипированные (динамические) переменные|динамический]]. Если же мы попытаемся присвоить этим переменным другие значения, заведомо неприводимого типа, то произойдет следующее:
 +
 
 +
<source lang="kpp">
 +
x = { |x| return x + 1; };
 +
y = [1, 2, 3];
 +
</source>
 +
 
 +
В случае переменной ''x'' будет сгенерирована ошибка еще на этапе компиляции, поскольку тип переменной был назначен статически при инициализации и не может быть изменен в ходе работы программы. В случае переменной ''y'' никакой ошибки не произойдет, поскольку это динамическая переменная. В ходе присваивания, она просто изменит свой тип на <tt>[[Стандартные типы данных#Массивы и списки|array]]</tt> и будет представлять собой уже массив из трех чисел.
 +
 
 +
----
 +
 
 +
 
 +
Объявления констант вместо <tt>'''var'''</tt>, начинаются с ключевого слова <tt>'''const'''</tt> и синтаксически ничем не отличаются от объявления переменных, за исключением того, что константы обязательно должны инициализироваться:
 +
 
 +
<source lang="kpp">
 +
const x;                    //неверно. требуется инициализатор
 +
const x = "hello";          //верно
 +
const x, y = 0;            //неверно. константа x не инициализируется
 +
const int x = "1", y = 1.5; //верно
 +
</source>
 +
 
 +
== Конструкция группового объявления ==
 +
 
 +
Существует также специальная конструкция, позволяющая объявить серию переменных и одновременно присвоить им значения из массива. Выглядит это следующим образом:
 +
 
 +
<source lang="kpp">
 +
var (x, y, z) = [1, '2', true];
 +
</source>
 +
 
 +
Будут объявлены три динамических переменных, инициализованные соответствующими элементами из массива. Размер массива должен быть не меньше количества объявляемых переменных. Если это не так, то переменные, которым не хватило элементов массива, не будут инициализированы.
 +
 
 +
Использование группового объявления особенно удобно при работе с функциями, возвращающими массив в качестве значения. Допустим, у нас есть операция, по логике работы возвращающая набор объектов. Такой результат можно описать в виде класса, полями которого будут значиться возвращаемые результаты. Тогда функция создает объект результат, устанавливает ему соответствующие значения свойств и возвращает его. В коде вызывающем функцию производится обратная операция, а именно заводится переменная под объект-результат и далее используется в коде обработки. В таком случае класс объекта-результата работает как структуры в С++.
 +
 
 +
Пример использования:
 +
<source lang="kpp">
 +
class QueryResult {
 +
    var FName, FAddress, FPhone;
 +
public:
 +
    property string name read FName;
 +
    property string address read FAddresss;
 +
    property string phoneNumber read FPhone;
 +
    operator new(_name, _addr, _phone) {
 +
        (FName, FAddress, FPhone) = [_name, _addr, _phone];
 +
    }
 +
}
 +
 
 +
function SearchByName(const string Name) {
 +
    // ... код обращения к БД ...
 +
    // предположим, были возвращены следующие данные:
 +
    var result = new QueryResult( 'Vassily Pupkin',
 +
        'Бобруйская область, село Урюпинское, д. 13', '223-322');
 +
    return result;
 +
}
 +
 
 +
function main() {
 +
    // ...
 +
    var result = SearchByName('%Pupkin%'); // делаем запрос
 +
    // работаем с результатами, используя result.name, result.address и result.phoneNumber
 +
    puts("Телефон Васи Пупкина: #{result.phoneNumber}");
 +
}
 +
</source>
 +
 
 +
В принципе подобный код вполне имеет право на существование, однако далеко не всегда удобно и эффективно городить огород из классов, только ради удобной передачи данных. Особенно если данный класс используется в единственном месте программы.
 +
 
 +
С использованием конструкции группового объявления, задача передачи и разбора параметров становится намного проще:
 +
<source lang="kpp">
 +
function SearchByName(const string Name) {
 +
    // ... код обращения к БД ...
 +
    // ... 'Vassily Pupkin', 'Бобруйская область, село Урюпинское, д. 13', '223-322'
 +
    return [ name, addr, phone ];
 +
}
 +
 
 +
function main() {
 +
    // ...
 +
    var (name, addr, phone) = SearchByName('%Pupkin%'); // делаем запрос   
 +
    puts("Телефон Васи Пупкина: #{phone}");
 +
}
 +
</source>
 +
 
 +
Функция, которой необходимо вернуть несколько значений оборачивает их в массив прямо по месту и возвращает одним объектом. В точке вызова производится обратная операция по вытаскиванию значений из массива и размещению в отдельных переменных.
 +
 
 +
 
 +
А вот простой способ разделить входную строку на подстроки и назначить каждой из них свою переменную:
 +
<source lang="kpp">
 +
var record = System.shellExecute("head -1 /etc/passwd"); // строка вида 'root:x:0:0:root:/root:/bin/bash'
 +
var (account, password, UID, GID, info, homedir, shell) = record.split(':');
 +
puts("Пользователь #{account} с номером #{UID} пользуется оболочкой #{shell} и хранит свои данные в #{homedir}");
 +
</source>
 +
 
 +
Метод [[string#split]] возвращает массив подстрок, поэтому зная результат выполнения метода мы можем произвести нашу операцию объявления переменных. Это намного удобнее, чем обращаться к элементам по индексам, тем самым избегая ошибок и опять же делая код более читаемым.
 +
 
 +
'''Примечание: ''' Существует также похожий синтаксис для оператора присваивания. Смысл точно такой же, как и у оператора объявления, только используются созданные ранее переменные. То есть, объявления переменных не происходит:
 +
 
 +
<source lang="kpp">
 +
var x = 1, y = 2; // объявление переменных
 +
(x, y) = [3, 4];  // групповое присваивание
 +
(x, y) = [y, x];  // простой способ обменять значения местами
 +
</source>
 +
 
 +
== Смотри также ==

Текущая версия на 14:49, 13 июля 2013

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

Вот несколько примеров объявления как одиночной переменной, так и группы переменных в рамках одного оператора:

<source lang="kpp" line="1"> var x; var x = "hello"; var x, y; var x, y = 0; var int x, y; var int x, real y; var int x = "1", y = 1.5; </source>

При объявлении переменных важно понимать, что при явном указании типа переменной, он сопостовляется только идентификатору идущему сразу после него. Таким образом, строка 5 объявляет переменную x типа int, в то время как переменная y будет иметь динамический тип.

То же самое относится и к инициализаторам, которые ставятся в соответствие только той переменной, которая стоит слева от оператора "=". К примеру, выражение в строке 4 будет инициализировать только переменную y, в то время как переменная x не будет иметь инициализатора; то есть для переменной x объявление эквивалентно тому что записано в строке 1.

Обратите внимание на строку 7: переменная x имеет инициализатор типа string, но ввиду того что тип переменной указан явным образом, переменная будет иметь тип int. При этом, тип инициализатора будет приведен к типу переменной. Если же типы переменной и инициализатора неприводимы, — будет выдано сообщение об ошибке.

Приведем еще раз те же самые примеры, но оформим их в виде таблицы, дополнив сведениями о типах переменых:

<source lang="kpp"> //Строка объявления Тип x Тип y Инициализатор x Инициализатор y

var x; динамика var x = "hello"; string "hello" var x, y; динамика динамика var x, y = 0; динамика int 0 var int x, y; int динамика var int x, real y; int real var int x = "1", y = 1.5; int real "1" as int 1.5 </source>

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

<source lang="kpp"> var x = 0; var y; y = 0; </source>

В результате выполнения этого кода и переменная x, и переменная y будут иметь значение равное 0. Более того, типы переменных в этот момент будут совпадать и равны int. Однако, переменная x будет иметь статический тип, в то время как переменная yдинамический. Если же мы попытаемся присвоить этим переменным другие значения, заведомо неприводимого типа, то произойдет следующее:

<source lang="kpp"> x = { |x| return x + 1; }; y = [1, 2, 3]; </source>

В случае переменной x будет сгенерирована ошибка еще на этапе компиляции, поскольку тип переменной был назначен статически при инициализации и не может быть изменен в ходе работы программы. В случае переменной y никакой ошибки не произойдет, поскольку это динамическая переменная. В ходе присваивания, она просто изменит свой тип на array и будет представлять собой уже массив из трех чисел.



Объявления констант вместо var, начинаются с ключевого слова const и синтаксически ничем не отличаются от объявления переменных, за исключением того, что константы обязательно должны инициализироваться:

<source lang="kpp"> const x; //неверно. требуется инициализатор const x = "hello"; //верно const x, y = 0; //неверно. константа x не инициализируется const int x = "1", y = 1.5; //верно </source>

[править] Конструкция группового объявления

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

<source lang="kpp"> var (x, y, z) = [1, '2', true]; </source>

Будут объявлены три динамических переменных, инициализованные соответствующими элементами из массива. Размер массива должен быть не меньше количества объявляемых переменных. Если это не так, то переменные, которым не хватило элементов массива, не будут инициализированы.

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

Пример использования: <source lang="kpp"> class QueryResult {

   var FName, FAddress, FPhone;

public:

   property string name read FName;
   property string address read FAddresss;
   property string phoneNumber read FPhone;
   operator new(_name, _addr, _phone) { 
       (FName, FAddress, FPhone) = [_name, _addr, _phone]; 
   }

}

function SearchByName(const string Name) {

   // ... код обращения к БД ...
   // предположим, были возвращены следующие данные:
   var result = new QueryResult( 'Vassily Pupkin', 
       'Бобруйская область, село Урюпинское, д. 13', '223-322');
   return result; 

}

function main() {

   // ...
   var result = SearchByName('%Pupkin%'); // делаем запрос
   // работаем с результатами, используя result.name, result.address и result.phoneNumber
   puts("Телефон Васи Пупкина: #{result.phoneNumber}");

} </source>

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

С использованием конструкции группового объявления, задача передачи и разбора параметров становится намного проще: <source lang="kpp"> function SearchByName(const string Name) {

   // ... код обращения к БД ...
   // ... 'Vassily Pupkin', 'Бобруйская область, село Урюпинское, д. 13', '223-322'
   return [ name, addr, phone ]; 

}

function main() {

   // ...
   var (name, addr, phone) = SearchByName('%Pupkin%'); // делаем запрос    
   puts("Телефон Васи Пупкина: #{phone}");

} </source>

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


А вот простой способ разделить входную строку на подстроки и назначить каждой из них свою переменную: <source lang="kpp"> var record = System.shellExecute("head -1 /etc/passwd"); // строка вида 'root:x:0:0:root:/root:/bin/bash' var (account, password, UID, GID, info, homedir, shell) = record.split(':'); puts("Пользователь #{account} с номером #{UID} пользуется оболочкой #{shell} и хранит свои данные в #{homedir}"); </source>

Метод string#split возвращает массив подстрок, поэтому зная результат выполнения метода мы можем произвести нашу операцию объявления переменных. Это намного удобнее, чем обращаться к элементам по индексам, тем самым избегая ошибок и опять же делая код более читаемым.

Примечание: Существует также похожий синтаксис для оператора присваивания. Смысл точно такой же, как и у оператора объявления, только используются созданные ранее переменные. То есть, объявления переменных не происходит:

<source lang="kpp"> var x = 1, y = 2; // объявление переменных (x, y) = [3, 4]; // групповое присваивание (x, y) = [y, x]; // простой способ обменять значения местами </source>

[править] Смотри также

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
информация
документация
Инструменты