Введение, или краткий обзор — различия между версиями
Korvin (обсуждение | вклад) м (→Здравствуй, мир!) |
Root (обсуждение | вклад) |
||
| Строка 24: | Строка 24: | ||
Теперь несколько слов о том, как такая программа будет запущена. | Теперь несколько слов о том, как такая программа будет запущена. | ||
| − | В первую очередь стоит отметить, что нет никаких стандартов на имя функции main или объекта STDOUT. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные STDIN, STDOUT и STDERR | + | В первую очередь стоит отметить, что нет никаких стандартов на имя функции main или объекта STDOUT. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные STDIN, STDOUT и STDERR, имеющие тип console_stream, и запускает функцию main, экспортируемую программой. |
Если бы мы, скажем, писали бы программу, генерирующую текстуру - никакой функции main в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации. | Если бы мы, скажем, писали бы программу, генерирующую текстуру - никакой функции main в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации. | ||
| Строка 33: | Строка 33: | ||
Ключевое слово export говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность перезагружать функции с одинаковыми именами но разными типами параметров. | Ключевое слово export говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность перезагружать функции с одинаковыми именами но разными типами параметров. | ||
| + | |||
| + | == Более сложный пример == | ||
| + | |||
| + | Вот более сложный пример, демонстрирующий использование переменных и циклов: | ||
| + | |||
| + | package sums; | ||
| + | import std; | ||
| + | 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]); | ||
| + | } | ||
| + | |||
| + | Смысл этой программы понятен интуитивно: создается два массива - исходный (ary) и результирующий (sums), и затем массив sums заполняется суммами чисел из массива ary от 0 до текущего индекса i. | ||
| + | |||
| + | Особое внимание в этом примере следует уделить объявлениям переменных. В строках 5 и 6 объявляются два массива - ary и sums - причем в инструкции var их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной (т.е. выражения, стоящего справа от =). | ||
| + | |||
| + | Выражения, записанные в квадратных скобках через запятую - это встроенная в K++ конструкция, создающая объект, имеющий тип array (объявленный в стандартной библиотеке) и заполненный соответствующими значениями. | ||
| + | |||
| + | Оператор new создает экземпляр произвольного класса - здесь мог бы стоять в том числе и пользовательский класс. В данном случае new создает экземпляр класса array. | ||
| + | |||
| + | Третья инструкция (строка 7) создает переменную типа int. Когда тип указан в самой конструкции var - объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны: | ||
| + | |||
| + | var sums = new array; | ||
| + | var sums = [ ]; | ||
| + | var array sums; | ||
| + | |||
| + | или | ||
| + | |||
| + | var i = 0; | ||
| + | var i = new int; | ||
| + | var int i; | ||
| + | |||
| + | Метод push класса array добавляет элемент в конец массива; size - возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит. | ||
| + | |||
| + | == Использование блоков == | ||
| + | |||
| + | Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторый связанный (с вызовом) блок кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который возвращает блок. | ||
| + | |||
| + | Выглядит это следующим образом: | ||
| + | |||
| + | package block_demo; | ||
| + | import std; | ||
| + | external console_stream STDOUT; | ||
| + | |||
| + | function void times(int i, block b) | ||
| + | { | ||
| + | var int n; | ||
| + | for(n = 0; n < i; ++n) | ||
| + | b(n); | ||
| + | } | ||
| + | |||
| + | export function void main() | ||
| + | { | ||
| + | times(3) { |i| STDOUT.print((i as string) + " "); }; | ||
| + | STDOUT.print("\n"); | ||
| + | } | ||
| + | |||
| + | Результат выполнения программы: | ||
| + | |||
| + | 0 1 2 | ||
| + | |||
| + | Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить - в этом случае будет сгенерирован [[Переменные#Динамическая типизация на примере Ruby|динамический код]]. | ||
| + | |||
| + | В функции main используется специальный синтаксис для вызова функции times: тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр-блок объявлен последним. | ||
| + | |||
| + | Можно было бы переписать эту конструкцию так: | ||
| + | |||
| + | var b = { |i| STDOUT.print((i as string) + " "); }; | ||
| + | times(3,b); | ||
| + | |||
| + | Параметры блока могут быть перечислены между символами "|" через запятую. В данном случае блок принимает один параметр - номер итерации. | ||
| + | |||
| + | == Расширение классов == | ||
| + | |||
| + | Приведенный выше пример можно переписать следующим образом: | ||
| + | |||
| + | package extend_demo; | ||
| + | import std; | ||
| + | external console_stream STDOUT; | ||
| + | |||
| + | extend int { | ||
| + | public const function void times(block b) | ||
| + | { | ||
| + | var int n; | ||
| + | for(n = 0; n < this; ++n) | ||
| + | b(n); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | export function void main() | ||
| + | { | ||
| + | 3.times() { |i| STDOUT.print((i as string) + " "); }; | ||
| + | STDOUT.print("\n"); | ||
| + | } | ||
| + | |||
| + | Оператор extend расширяет функционал класса - в данном случае класса int. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу. | ||
| + | |||
| + | Таким образом, к классу int, объявленному в стандартной библиотеке, добавляется метод times, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс int, который отвечает за хранение числа). | ||
| + | |||
| + | После такого объявления, в функции main мы используем уже метод times класса int: конструкция 3.times() означает создание объекта 3 класса int и вызов у этого объекта метода times(). | ||
Версия 11:01, 6 сентября 2007
Содержание |
(Введение...)
Здравствуй, мир!
Классический пример программы, выводящей строку "Hello, world!" на экран, на языке K++ выглядит следующим образом:
Как уже отмечалось ранее, в K++ любая программа или библиотека является модулем. Первая строчка данной программы задает имя модуля, в который будет скомпилирована программа.
Стандартные типы данных, такие как строки, целые числа, а также класс console_stream, объявлены в модуле std - третья строчка программы подключает этот модуль.
Теперь несколько слов о том, как такая программа будет запущена.
В первую очередь стоит отметить, что нет никаких стандартов на имя функции main или объекта STDOUT. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды gide.run, реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные STDIN, STDOUT и STDERR, имеющие тип console_stream, и запускает функцию main, экспортируемую программой.
Если бы мы, скажем, писали бы программу, генерирующую текстуру - никакой функции main в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации.
Четвертая строчка программы объявляет глобальную переменную STDOUT, имеющую тип console_stream, как внешнюю - т.е. создаваемую пользователем.
И, наконец, строки 6-9 задают функцию main, которая вызывает метод print объекта STDOUT, передав ему строку "Hello, world!\n" в качестве параметра.
Ключевое слово export говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность перезагружать функции с одинаковыми именами но разными типами параметров.
Более сложный пример
Вот более сложный пример, демонстрирующий использование переменных и циклов:
package sums;
import std;
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]);
}
Смысл этой программы понятен интуитивно: создается два массива - исходный (ary) и результирующий (sums), и затем массив sums заполняется суммами чисел из массива ary от 0 до текущего индекса i.
Особое внимание в этом примере следует уделить объявлениям переменных. В строках 5 и 6 объявляются два массива - ary и sums - причем в инструкции var их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной (т.е. выражения, стоящего справа от =).
Выражения, записанные в квадратных скобках через запятую - это встроенная в K++ конструкция, создающая объект, имеющий тип array (объявленный в стандартной библиотеке) и заполненный соответствующими значениями.
Оператор new создает экземпляр произвольного класса - здесь мог бы стоять в том числе и пользовательский класс. В данном случае new создает экземпляр класса array.
Третья инструкция (строка 7) создает переменную типа int. Когда тип указан в самой конструкции var - объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны:
var sums = new array; var sums = [ ]; var array sums;
или
var i = 0; var i = new int; var int i;
Метод push класса array добавляет элемент в конец массива; size - возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит.
Использование блоков
Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторый связанный (с вызовом) блок кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который возвращает блок.
Выглядит это следующим образом:
package block_demo;
import std;
external console_stream STDOUT;
function void times(int i, block b)
{
var int n;
for(n = 0; n < i; ++n)
b(n);
}
export function void main()
{
times(3) { |i| STDOUT.print((i as string) + " "); };
STDOUT.print("\n");
}
Результат выполнения программы:
0 1 2
Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить - в этом случае будет сгенерирован динамический код.
В функции main используется специальный синтаксис для вызова функции times: тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр-блок объявлен последним.
Можно было бы переписать эту конструкцию так:
var b = { |i| STDOUT.print((i as string) + " "); };
times(3,b);
Параметры блока могут быть перечислены между символами "|" через запятую. В данном случае блок принимает один параметр - номер итерации.
Расширение классов
Приведенный выше пример можно переписать следующим образом:
package extend_demo;
import std;
external console_stream STDOUT;
extend int {
public const function void times(block b)
{
var int n;
for(n = 0; n < this; ++n)
b(n);
}
}
export function void main()
{
3.times() { |i| STDOUT.print((i as string) + " "); };
STDOUT.print("\n");
}
Оператор extend расширяет функционал класса - в данном случае класса int. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу.
Таким образом, к классу int, объявленному в стандартной библиотеке, добавляется метод times, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс int, который отвечает за хранение числа).
После такого объявления, в функции main мы используем уже метод times класса int: конструкция 3.times() означает создание объекта 3 класса int и вызов у этого объекта метода times().
