Правый вариант короче, но понять его очень сложно. Есть даже специальный класс программ (обфускаторы), которые делают исходные тексты непригодными для чтения, при этом оставляя их работоспособными. Фигурные скобки встречаются очень часто. Мы можем фрагмент из предыдущего примера написать так if !( array[i] & 1 ) { result += array[i] } а можем использовать ':', который весь текст до конца строки включает в фигурные скобки. if !( array[i] & 1 ) : result += array[i] Кроме понятных имен и правильного форматирования не забывайте о комментариях. Комментируйте то, что вам не будет очевидно из текста через какое-то время. Комментарии - это основные помощники в документировании ваших программ. Они бывают двух видов:
ФункцияФункция - это основной "строительный" элемент, из которых создаются программы. Каждая функция производит одни и те же определенные вычисления. Функция может возвращать значение и принимать входящие параметры, от которых зависит результат выполнения. Вот примеры описания функций: func myfunc func uint my( uint i j k ) // Три параметра i j k типа uint func sum( uint left, int right ) Каждая функция должна иметь блок кода заключенный в фигурные скобки. Он описывает поведение функции. Это может быть последовательноть выражений, условных конструкций, циклов. В нем также должны быть описаны локальные переменные. Локальные переменные - это ячейки или объекты для временного хранения результатов. Локальные переменные могут быть у любой функции и могут быть описаны в любом ее месте. Если переменные или параметры одного типа, то они разделяются пробелами. Если они имеют разные типы, то параметры разделяются запятыми, а переменные разных типов начинаются с новой строки. Рассмотрим пример функции выводящей сумму, разность, произведение и частное двух целых чисел. Я использовал локальную переменную для хранения произведения двух чисел в качестве простейшего примера. func myout( int i j ) { int multi multi = i * j @"\(i) + \(j) = \( i + j ) \(i) - \(j) = \( i - j ) \(i) * \(j) = \( multi ) \(i) / \(j) = \( i / j )\n" } func main<main> { myout( 20, 10 ) myout( 567, 35 ) myout( 16, 4 ) } В зависимости от различных значений параметров i и j функция myout будет выдавать различные результаты. В данном примере у нас имеется одна операция присваивания '='. Она позволяет устанавливать у переменных новые значения. При вызове функции локальные переменные равны нулю, но можно присваивать значение локальным переменным сразу после их описания. uint i = 10 i = i * 5 + 2После выполнения этого фрагмента значение i будет равно 52. МетодМетод отличается от функции только описанием и способом вызова. Использование метода лучше дает понять, что над определенным объектом мы производим какое-то действие. // Описание method [возвращаемый_тип] тип_переменной.имя_метода( параметры ) // Использование переменная.имя_метода( параметры )Попробуем сделать фунцию print методом. method str.myprint : print( this ) func main<main> { str hello = "Hello!" hello.myprint() getch() } this обозначает переменную с которой вызывается метод. В данном случае можно обойтись без дополнительной переменной hello. Строка в двойных кавычках является обыкновенной переменной типа str, только без имени. Вы просто не можете к ней обратиться в дальнейшем. "Hello!".myprint() В объектно-оиентированных языках методы жестко привязаны к конкретному классу и для добавления своих методов требуется определение нового класса на основе существующего. Gentee позволяет добавлять новые методы к типам в любой момент и в любом месте. Компилятор Gentee строго следит за правильностью типов переменных и параметров. С одной стороны, это может доставить неудобства, но с другой стороны, это позволяет избежать многих ошибок и также можно описывать функции и методы с одинаковыми именами, но разными параметрами. Компилятор сам определит необходимую функцию или метод при вызове. Добавим для иллюстрации еще один метод myprint, который будет выводить строку указанное количество раз. method str.myprint : print( this ) method str.myprint( uint count ) { str s = this + "\n" print( s.repeat( count )) } func main<main> { "Hello!".myprint() "-----".myprint( 5 ) getch() } Консольный ввод и выводКак вы уже заметили, все рассмотренные примеры просто выводили текст в отдельное окно. Изначально, можно было выводить на экран монитора только символы. С развитием компьютеров, появилась возможсноть выводить графику и появился оконный интерфейс, к которому мы все привыкли. Тем не менее многим программам для их работы оконный интерфейс просто не нужен или им достаточно текстового ввода и вывода. Эти программы называются консольными. В данном руководстве все мои примеры работают только с консолью, то есть осуществляют только текстовый ввод и вывод. Во-первых, этих возможностей вполне достаточно, чтобы научиться программировать. Во-вторых, программированию оконных интерфейсов будет посвящено отдельное руководство. Как правило, создание консольного приложения требует минимум дополнительных затрат без ограничения функциональности. Так как я уже много раз использовал вывод данных с помощью функции print и операции @"строка вывода", то перейдем сразу к вводу данных. Хочу сделать небольшое отступление для тех пользователей у которых вывод на консоль национальных символов дает неверный результат. Например, вывод русского текста под Windows print("Привет!") даст непонятный набор символов. Никакой ошибки тут нет, это наследие операционной системы MS-DOS. У каждой системы есть своя кодировка, и не одна. Консольные приложения Windows используют кодировку из MS-DOS, а вы набиваете текст в кодировке Windows. И если кодировка латинских букв алфавита совпадают в обоих случаях, то расположение русских символов абсолютно разное. Поэтому английский текст выводится правильно, а русский текст нечитаем. Попробуйте вот этот фрагмент: print("?аЁў?в!") Он выведет именно то, что вы и ожидали увидеть раньше. Решить эту проблему можно с помощью методов oem2char и char2oem. Первый переводит строку из DOS кодировки в Windows, а второй осуществляет обратную операция. print( "Привет!".char2oem()) Можно определить свою функцию для вывода. Я использую в ней временную переменную, чтобы не портить передаваемую строку. func myprint( str out ) { str dos = out print( dos.char2oem()) } Одну функцию для ввода данных вы уже знаете. Это getch, которая используется для получения нажатой клавиши. Для получение целой строки можно использовать функцию congetstr( str outtext intext ). В первом параметре можно указать выводимы текст, а вторая строка служит для получения результата. Вывод заканчивается при нажатии клавиши Enter. str in congetstr( "Enter your name: ", in ) print("Your name: \(in)\n") Конструкция условияОператор условия позволяет изменять порядок выполнения программы в зависимости от истинности условного выражения. Условный оператор присутствует в любом языке программирования и является одним из фундаментальных понятий. В Gentee оператор условия выглядит так: if условное_выражение1 { // Выполняется если условное_выражение1 не 0 } elif условное_выражение2 { // Выполняется если условное_выражение2 не 0 } else { // Выполняется если все предыдущие условия ложь. } Дополнительные конструкции elif и else не являеются обязательными. Может быть указано несколько конструкций elif. Переход к ним происходит если ни одно из предыдущих условий не было выполнено. Условным выражением является любое выражение возвращающее число. Нулевое значение означает, что выражение ЛОЖНО, в противном случае выражение является ИСТИННЫМ. В простейшем случае выражением может быть переменная. uint i if i { ... }Имеются специальные операции сравнения. a < b - возвратит 1 если a меньше
b и 0 в остальных случаях. Следует заметить, что для равенства используется два знака '=', в отличии от операции присваивания. В приведенном ниже примере тело условного оператора будет выполнятся в любом случае, так как оператор присваивания сделает значение переменной i равным 1 и возвратит его. if i = 1 {...}Правильный вариант if i == 1 {...} Сейчас мы можем написать функцию нахождения минимального значения из двух чисел. func int mymin( int left right ) { if left < right : return left return right } Мы не указали else потому что при left меньше right мы выходим из функции. Кроме операций сравнения существуют три логические операции:a && b - возвратит 1 если a и
b не ноль. В остальных случаях возвратит 0. Усложним предыдущий пример и напишем функцию нахождения суммы двух минимальных чисел из трех переданных в параметре. Рассмотрим три варианта решения. // Пример 1 func int mymin( int left right ) : return ?( left < right, left, right ) func int mymin( int x y z ) : return mymin( x + y, mymin( x + z, y + z )) Данное решение очень компактное. Мы сразу берем три возможные суммы и ищем среди них минимальную. Вы заметили, что у нас функции имеют одинаковое название. Это еще одна иллюстрация возможности определения функций и методов с одним и тем же именем. Оператор?( условное выражение, выражение1, выражение2 ) является аналогом конструкции условия для использования внутри выражений. В зависимости от результата условия будет вычислено и возвращено выражение1 или выражение2. Рассмотрим второй пример// Пример 2 func int mymin( int x y z ) { if x < z { if y < z : return x + y return x + z } if x < y : return x + z return y + z } Смотрим, если x меньше z, то считаем, что одно минимально число мы уже нашли. Остается сравнить y и z и возвратить соответствующую сумму. Если x не меньше z, то тогда остается только сравнить x и y и возвратить сумму меньшего из них и z. В третьем варианте мы будем искать максимальное число и возвращать сумму двух остальных чисел. // Пример 3 func int mymin( int x y z ) { if x > y && x > z : return y + z if y > z : return x + z return x + y } После первой условной конструкции мы выяснили, что x не является максимальным. Значит будем возвращать или x + y или x + z. Нам достаточно только определить наименьшее из y и z. Для тестирования можно определить ниже функцию main и запускать ее с разными параметрами при вызове mymin. func main<main> { print("MIN( x, y, z ) = \( mymin( 12, 45, 34 ))") getch() } ЦиклыЦиклы позволяют повторить необходимое количество раз определенную последовательность действий. В Gentee имеется несколько видов циклов и сейчас я познакомлю с тремя из них. Попробуем найти сумму чисел от 1 до 100. Для решения этой задачи лучше всего подойдет цикл fornum. fornum переменная_счетчик [ = начальное_значение ], конечное_значение { // тело цикла } Значение переменной-счетчика увеличивается на 1 после каждого прохода. Присваивание начального значения может отсутствовать. Важно отметить, что конечное значение должно быть на 1 больше, чем вам необходимо. Решить задачу суммирования можно следующим образом: func main<main> { uint i sum fornum i, 101 : sum += i @"SUM (1 - 100) = \(sum)" getch() } Я думаю вы не забыли, что все переменные в начале равны нулю, поэтому их можно использовать без дополнительной инициализации. Операция a += b равнозначна операции a = a + b. Есть аналогичные операции для вычитания, умножения и деления -=, *=, /= . Например, в результате i *= 3 значение переменной i увеличится в три раза. Вторым простым циклом является while, кторый исполняет тело цикла пока условное выражение не равно 0. while условное_выражение { // тело цикла } Попробуйте решить предыдущую задачу используя while вместо fornum. Учтите, что вы должны сами изменять значение переменной i. Я в качестве иллюстрации использования while приведу пример получения и вывода символа с клавиатуры. func main<main> { uint ch while (ch = getch()) != 'q' { print( "Key: ".appendch( ch ) += "\n" ) } } Цикл будет работать до тех пор, пока мы не нажмем клавишу 'q'. Метод appendch добавляет к строке символ с данным значением. Если мы напишем такprint( "Key: \( ch ) \n" )то у нас будут выводиться числовые значение нажатых клавиш. Аналогично while работает цикл do while. Единственное отличие в том, что в do while проверка производится после выполнения тела цикла. Цикл выполнится как минимум один раз. do { // тело цикла } while условное_выражение В следующем примере цикл do while в отличии от while выполнится один раз. i = 10 while i < 10 : @"While: \( i )" do { @"Do While: \( i )" } while i < 10 Определение типаВсе вещи вокруг нас можно классифицировать и разбить на различные группы. Все животные и растения разбиваются на классы и виды. Возьмем строения. Есть офисные здания, магазины, жилые многоквартирные дома, коттеджи и т.д. Принадлежность к какой-то группе подразумевает определенные свойства данного объекта. Тоже самое с типами в программировании. Вы уже немного знакомы с натуральными числами uint и строками str. Нам встречался еще тип int - это целое число от -2147483648 до +2147483647. Есть типы float и double для работы с действительными числами. Есть long и ulong представляющие очень большие числа. Самое главное то, что вы сами можете определять свои типы и работать с ними. Рассмотрим конкретный пример создания типа ( или структуры ). type person { str firstname str lastname str email uint age // Возраст } Наш тип person имеет четыре поля для хранения имени, email и возраста. При описании структуры для каждого поля необходимо указать его тип и имя, по которому мы будем обращаться к данному полю. Желательно, чтобы имена полей указывали на ту информацию, которую они будут хранить или имели соответствующие комментарии. Определим методы для установки значений полей и для их вывода на экран. method person person.set( str fname lname email, uint age ) { this.firstname = fname this.lastname = lname this.email = email this.age = age return this } method person.print { print( "Name: \(this.firstname) \(this.lastname) Email: \(this.email) Age: \(this.age)\n" ) } Из примера видно, что обращение к полям происходит с использованием '.' подобно вызову метода. Больше ничего нового и сложного нет и остается добавить главную функцию. Пример простейший, но в дальнейшем мы познакомимся и будем работать с очень полезными типами. func main<main> { person myf myf.set( "Alexey", "Krivonogov", "info@gentee.com", 34 ).print() getch() } Благодаря тому, что метод set возвращает сам объект типа person мы можем сразу же применить метод print. Такой последовательный вызов методов сокращает программу, но оставляет ее по-прежнему понятной. Источник: http://www.gentee.ru/vol1.htm Автор: Алексей Кривоногов
|