Введение, или краткий обзор — различия между версиями
Korvin (обсуждение | вклад) м (→Расширение классов) |
Raw mat (обсуждение | вклад) |
||
(не показаны 15 промежуточных версий 10 участников) | |||
Строка 10: | Строка 10: | ||
package hello_world; | package hello_world; | ||
− | + | export function void main() { | |
− | + | print("Hello, world!\n"); | |
− | + | ||
− | export function void main() | + | |
− | { | + | |
− | + | ||
} | } | ||
</source> | </source> | ||
Строка 22: | Строка 18: | ||
;1: Как уже [[Модули|отмечалось ранее]], в K++ любая программа или библиотека является модулем. Ключевое слово <tt>'''package'''</tt> используется для объявления имени модуля, в который должна быть скомпилирована программа. | ;1: Как уже [[Модули|отмечалось ранее]], в K++ любая программа или библиотека является модулем. Ключевое слово <tt>'''package'''</tt> используется для объявления имени модуля, в который должна быть скомпилирована программа. | ||
− | ;3 | + | ;3-5: Наконец, объявляется функция <tt>main()</tt>, которая вызывает системную функцию <tt>print()</tt> [[Стандартная библиотека Gide|стандартной библиотеки]], передав ей строку "Hello, world!\n" в качестве параметра. Пара символов <tt>'''\n'''</tt> является специальной последовательностью, которая в момент компиляции преобразуется в символ перевода строки. |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
+ | : Ключевое слово <tt>'''export'''</tt> говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность [[Функции#Перегрузка функций и операторов|перегружать функции]] с одинаковыми именами, но разными списками параметров (или параметрами разных типов), а так же для реализации [[Пространства имен|пространств имен]]. | ||
+ | <!-- | ||
Теперь несколько слов о том, как такая программа будет запущена. В первую очередь стоит отметить, что нет никаких стандартов на имя функции <tt>main()</tt> или объекта ''STDOUT''. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные ''STDIN'', ''STDOUT'' и ''STDERR'', имеющие тип <tt>console_stream</tt> и запускает функцию <tt>main()</tt>, экспортируемую программой. | Теперь несколько слов о том, как такая программа будет запущена. В первую очередь стоит отметить, что нет никаких стандартов на имя функции <tt>main()</tt> или объекта ''STDOUT''. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные ''STDIN'', ''STDOUT'' и ''STDERR'', имеющие тип <tt>console_stream</tt> и запускает функцию <tt>main()</tt>, экспортируемую программой. | ||
− | Если бы мы, скажем, писали | + | Если бы мы, скажем, писали программу, генерирующую текстуру — никакой функции <tt>main()</tt> в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации. --> |
== Более сложный пример == | == Более сложный пример == | ||
Строка 41: | Строка 33: | ||
<source lang="kpp" line="1"> | <source lang="kpp" line="1"> | ||
package sums; | package sums; | ||
− | + | ||
− | export function void main() | + | export function void main() { |
− | { | + | |
var ary = [ 1, 2, 3, 4 ]; | var ary = [ 1, 2, 3, 4 ]; | ||
var sums = new array; | var sums = new array; | ||
var int i; | var int i; | ||
sums.push(ary[0]); | sums.push(ary[0]); | ||
− | for(i = 1; i < ary.size(); ++i) | + | for (i = 1; i < ary.size(); ++i) |
sums.push(sums[i-1] + ary[i]); | sums.push(sums[i-1] + ary[i]); | ||
} | } | ||
Строка 55: | Строка 46: | ||
Смысл этой программы понятен интуитивно: создается два массива — исходный (''ary'') и результирующий (''sums''), и затем массив ''sums'' заполняется суммами чисел из массива ''ary'' от 0 до текущего индекса i. | Смысл этой программы понятен интуитивно: создается два массива — исходный (''ary'') и результирующий (''sums''), и затем массив ''sums'' заполняется суммами чисел из массива ''ary'' от 0 до текущего индекса i. | ||
− | ; | + | ;4-5: Особое внимание в этом примере следует уделить объявлениям переменных. Мы видим, что объявляются два [[Стандартные типы данных#Массивы|массива]] — ''ary'' и ''sums'', причем в инструкции <tt>'''var'''</tt> их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной, т.е. выражения, стоящего справа от оператора '<tt>=</tt>'. |
− | :Выражения, записанные в квадратных скобках через запятую — это встроенная в K++ конструкция, создающая объект, имеющий тип <tt>[[Стандартные типы данных#Массивы|array]]</tt> (объявленный в [[Стандартная | + | :Выражения, записанные в квадратных скобках через запятую — это встроенная в K++ конструкция, создающая объект, имеющий тип <tt>[[Стандартные типы данных#Массивы|array]]</tt> (объявленный в [[Стандартная библиотека gide|стандартной библиотеке]]) и заполненный соответствующими значениями. |
− | :Оператор <tt>'''new'''</tt> создает экземпляр произвольного класса — здесь мог бы стоять в том числе и пользовательский класс. В данном случае <tt>'''new'''</tt> создает экземпляр класса <tt>[[Стандартные типы данных#Массивы|array]]</tt>. | + | :Оператор <tt>'''new'''</tt> создает экземпляр произвольного класса — здесь мог бы стоять, в том числе, и пользовательский класс. В данном случае <tt>'''new'''</tt> создает экземпляр класса <tt>[[Стандартные типы данных#Массивы|array]]</tt>. |
− | ; | + | ;6: Здесь мы создаем переменную типа <tt>[[Стандартные типы данных#Целые числа|int]]</tt>. Когда тип указан в самой конструкции <tt>'''var'''</tt> — объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны: |
<source lang="kpp"> | <source lang="kpp"> | ||
Строка 87: | Строка 78: | ||
<source lang="kpp" line="1"> | <source lang="kpp" line="1"> | ||
package block_demo; | package block_demo; | ||
− | |||
− | |||
− | function void times(int i, block b) | + | function void times(int i, block b) { |
− | { | + | for (var n = 0; n < i; n++) |
− | + | ||
− | for(n = 0; n < i; ++ | + | |
b(n); | b(n); | ||
} | } | ||
− | export function void main() | + | export function void main() { |
− | { | + | times(3) { |i| print((i as string) + " "); }; |
− | times(3) { |i| | + | print("\n"); |
− | + | ||
} | } | ||
</source> | </source> | ||
Строка 110: | Строка 96: | ||
Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить — в этом случае будет сгенерирован [[Переменные#Динамическая типизация на примере Ruby|динамический код]]. | Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить — в этом случае будет сгенерирован [[Переменные#Динамическая типизация на примере Ruby|динамический код]]. | ||
− | ; | + | ;4: Обратите внимание на то, что управляющая переменная создается непосредственно по месту использования, то есть в [[Основные синтаксические конструкции#Цикл_for|цикле <tt>'''for'''</tt>]]. Такой подход является предпочтительным по сравнению с подходом, при котором управляющая переменная создается за пределами цикла. Почему это так, будет сказано в отдельном разделе, посвященном циклам. |
+ | |||
+ | ;10:В функции <tt>main()</tt> используется специальный синтаксис для вызова функции <tt>times()</tt>: тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр—блок объявлен последним. | ||
Можно было бы переписать эту конструкцию так: | Можно было бы переписать эту конструкцию так: | ||
<source lang="kpp"> | <source lang="kpp"> | ||
− | var b = { |i| | + | var b = { |i| print((i as string) + " "); }; |
times(3,b); | times(3,b); | ||
</source> | </source> | ||
Строка 127: | Строка 115: | ||
<source lang="kpp" line="1"> | <source lang="kpp" line="1"> | ||
package extend_demo; | package extend_demo; | ||
− | |||
− | |||
extend int { | extend int { | ||
− | public const function void times(block b) | + | public const function void times(block b) { |
− | + | for (var n = 0; n < this; n++) | |
− | + | ||
− | for(n = 0; n < this; ++ | + | |
b(n); | b(n); | ||
} | } | ||
} | } | ||
− | export function void main() | + | export function void main() { |
− | { | + | 3.times() { |i| print((i as string) + " "); }; |
− | 3.times() { |i| | + | print("\n"); |
− | + | ||
} | } | ||
</source> | </source> | ||
− | + | ;3-8: Оператор <tt>'''extend'''</tt> расширяет функционал класса — в данном случае класса <tt>[[Стандартные типы данных#Целые числа|int]]</tt>. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу. | |
− | ; | + | |
: Таким образом, к классу <tt>int</tt>, объявленному в стандартной библиотеке, добавляется метод <tt>times()</tt>, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс <tt>int</tt>, который отвечает за хранение числа). | : Таким образом, к классу <tt>int</tt>, объявленному в стандартной библиотеке, добавляется метод <tt>times()</tt>, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс <tt>int</tt>, который отвечает за хранение числа). | ||
− | ; | + | ;11: После такого объявления, в функции <tt>main()</tt> мы используем уже метод <tt>times()</tt> класса <tt>int</tt>: конструкция <tt>3.times()</tt> означает создание объекта 3 класса <tt>int</tt> и вызов у этого объекта метода <tt>times()</tt>. |
'''Примечание:''' Расширение будет работать во всем модуле, а так же во всех модулях, которые импортируют данный модуль. | '''Примечание:''' Расширение будет работать во всем модуле, а так же во всех модулях, которые импортируют данный модуль. |
Текущая версия на 13:43, 13 июля 2013
Содержание |
(Введение...)
[править] Здравствуй, мир!
Классический пример программы, выводящей строку "Hello, world!" на экран, на языке K++ выглядит следующим образом:
<source lang="kpp" line="1"> package hello_world;
export function void main() {
print("Hello, world!\n");
} </source>
- 1
- Как уже отмечалось ранее, в K++ любая программа или библиотека является модулем. Ключевое слово package используется для объявления имени модуля, в который должна быть скомпилирована программа.
- 3-5
- Наконец, объявляется функция main(), которая вызывает системную функцию print() стандартной библиотеки, передав ей строку "Hello, world!\n" в качестве параметра. Пара символов \n является специальной последовательностью, которая в момент компиляции преобразуется в символ перевода строки.
- Ключевое слово export говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность перегружать функции с одинаковыми именами, но разными списками параметров (или параметрами разных типов), а так же для реализации пространств имен.
[править] Более сложный пример
Вот более сложный пример, демонстрирующий использование переменных и циклов:
<source lang="kpp" line="1"> package sums;
export function void main() {
var ary = [ 1, 2, 3, 4 ]; var sums = new array; var int i; sums.push(ary[0]); for (i = 1; i < ary.size(); ++i) sums.push(sums[i-1] + ary[i]);
} </source>
Смысл этой программы понятен интуитивно: создается два массива — исходный (ary) и результирующий (sums), и затем массив sums заполняется суммами чисел из массива ary от 0 до текущего индекса i.
- 4-5
- Особое внимание в этом примере следует уделить объявлениям переменных. Мы видим, что объявляются два массива — ary и sums, причем в инструкции var их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной, т.е. выражения, стоящего справа от оператора '='.
- Выражения, записанные в квадратных скобках через запятую — это встроенная в K++ конструкция, создающая объект, имеющий тип array (объявленный в стандартной библиотеке) и заполненный соответствующими значениями.
- Оператор new создает экземпляр произвольного класса — здесь мог бы стоять, в том числе, и пользовательский класс. В данном случае new создает экземпляр класса array.
- 6
- Здесь мы создаем переменную типа int. Когда тип указан в самой конструкции var — объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны:
<source lang="kpp"> var sums = new array; var sums = [ ]; var array sums; </source>
или
<source lang="kpp"> var i = 0; var i = new int; var int i; </source>
Метод push() класса array добавляет элемент в конец массива; size() — возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит.
[править] Использование блоков
Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторого связанного (с вызовом) блока кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который он возвращает.
Выглядит это следующим образом:
<source lang="kpp" line="1"> package block_demo;
function void times(int i, block b) {
for (var n = 0; n < i; n++) b(n);
}
export function void main() {
times(3) { |i| print((i as string) + " "); }; print("\n");
} </source>
Результат выполнения программы:
0 1 2
Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить — в этом случае будет сгенерирован динамический код.
- 4
- Обратите внимание на то, что управляющая переменная создается непосредственно по месту использования, то есть в цикле for. Такой подход является предпочтительным по сравнению с подходом, при котором управляющая переменная создается за пределами цикла. Почему это так, будет сказано в отдельном разделе, посвященном циклам.
- 10
- В функции main() используется специальный синтаксис для вызова функции times(): тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр—блок объявлен последним.
Можно было бы переписать эту конструкцию так:
<source lang="kpp"> var b = { |i| print((i as string) + " "); }; times(3,b); </source>
Параметры блока могут быть перечислены между символами "|" через запятую. В данном случае блок принимает один параметр — номер итерации.
[править] Расширение классов
Приведенный выше пример можно переписать следующим образом:
<source lang="kpp" line="1"> package extend_demo;
extend int {
public const function void times(block b) { for (var n = 0; n < this; n++) b(n); }
}
export function void main() {
3.times() { |i| print((i as string) + " "); }; print("\n");
} </source>
- 3-8
- Оператор extend расширяет функционал класса — в данном случае класса int. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу.
- Таким образом, к классу int, объявленному в стандартной библиотеке, добавляется метод times(), вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс int, который отвечает за хранение числа).
- 11
- После такого объявления, в функции main() мы используем уже метод times() класса int: конструкция 3.times() означает создание объекта 3 класса int и вызов у этого объекта метода times().
Примечание: Расширение будет работать во всем модуле, а так же во всех модулях, которые импортируют данный модуль.