# — так начинается комментарий# Всё является объектомnil.class#=> Nil100.class#=> Int32true.class#=> Bool# Возвращают false только nil, false и пустые указатели!nil#=> true : Bool!false#=> true : Bool!0#=> false : Bool# Целые числа1.class#=> Int32# Четыре типа целых чисел со знаком1_i8.class#=> Int81_i16.class#=> Int161_i32.class#=> Int321_i64.class#=> Int64# Четыре типа целых чисел без знака1_u8.class#=> UInt81_u16.class#=> UInt161_u32.class#=> UInt321_u64.class#=> UInt642147483648.class#=> Int649223372036854775808.class#=> UInt64# Двоичные числа0b1101#=> 13 : Int32# Восьмеричные числа0o123#=> 83 : Int32# Шестнадцатеричные числа0xFE012D#=> 16646445 : Int320xfe012d#=> 16646445 : Int32# Числа с плавающей точкой1.0.class#=> Float64# Два типа чисел с плавающей запятой1.0_f32.class#=> Float321_f32.class#=> Float321e10.class#=> Float641.5e10.class#=> Float641.5e-7.class#=> Float64# Символьные литералы'a'.class#=> Char# Восьмеричный код символа'\101'#=> 'A' : Char# Код символа Unicode'\u0041'#=> 'A' : Char# Строки"s".class#=> String# Строки неизменяемыs="hello, "#=> "hello, " : Strings.object_id#=> 134667712 : UInt64s+="Crystal"#=> "hello, Crystal" : Strings.object_id#=> 142528472 : UInt64# Поддерживается интерполяция строк"sum = #{1+2}"#=> "sum = 3" : String# Поддерживается многострочность"This is
multiline string"# Строка с двойными кавычками%(hello "world")#=> "hello \"world\""# Символы — константы без значения, определяемые только именем. Часто# используются вместо часто используемых строк для лучшей производительности.# На внутреннем уровне они представлены как Int32.:symbol.class#=> Symbolsentence=:question?# :"question?" : Symbolsentence==:question?#=> true : Boolsentence==:exclamation!#=> false : Boolsentence=="question?"#=> false : Bool# Массивы[1,2,3].class#=> Array(Int32)[1,"hello",'x'].class#=> Array(Int32 | String | Char)# При объявлении пустого массива необходимо указать тип его элементов[]# Syntax error: for empty arrays use '[] of ElementType'[]ofInt32#=> [] : Array(Int32)Array(Int32).new#=> [] : Array(Int32)# Элементы внутри массива имеют свои индексыarray=[1,2,3,4,5]#=> [1, 2, 3, 4, 5] : Array(Int32)array[0]#=> 1 : Int32array[10]# raises IndexErrorarray[-6]# raises IndexErrorarray[10]?#=> nil : (Int32 | Nil)array[-6]?#=> nil : (Int32 | Nil)# Можно получать элементы по индексу с концаarray[-1]#=> 5# С начала и с указанием размера итогового массиваarray[2,3]#=> [3, 4, 5]# Или посредством указания диапазонаarray[1..3]#=> [2, 3, 4]# Добавление в массивarray<<6#=> [1, 2, 3, 4, 5, 6]# Удаление элемента из конца массиваarray.pop#=> 6array#=> [1, 2, 3, 4, 5]# Удаление элемента из начала массиваarray.shift#=> 1array#=> [2, 3, 4, 5]# Проверка на наличие элемента в массивеarray.includes?3#=> true# Синтаксический сахар для массива строк и символов%w(one two three)#=> ["one", "two", "three"] : Array(String)%i(one two three)#=> [:one, :two, :three] : Array(Symbol)# Массивоподобный синтаксис используется и для других типов, только если для# них определены методы .new и #<<set=Set{1,2,3}#=> [1, 2, 3]set.class#=> Set(Int32)# Вышеприведенное эквивалентно следующемуset=Set(typeof(1,2,3)).newset<<1set<<2set<<3# Хэши{1=>2,3=>4}.class#=> Hash(Int32, Int32){1=>2,'a'=>3}.class#=> Hash(Int32 | Char, Int32)# При объявлении пустого хэша необходимо указать типы ключа и значения{}# Syntax error{}ofInt32=>Int32# {}Hash(Int32,Int32).new# {}# Значения в хэше легко найти по ключуhash={"color"=>"green","number"=>5}hash["color"]#=> "green"hash["no_such_key"]#=> Missing hash key: "no_such_key" (KeyError)hash["no_such_key"]?#=> nil# Проверка наличия ключа в хэшеhash.has_key?"color"#=> true# Синтаксический сахар для символьных и строковых ключей{key1:'a',key2:'b'}# {:key1 => 'a', :key2 => 'b'}{"key1":'a',"key2":'b'}# {"key1" => 'a', "key2" => 'b'}# Хэшеподобный синтаксис используется и для других типов, только если для них# определены методы .new и #[]=classMyTypedef[]=(key,value)puts"do stuff"endendMyType{"foo"=>"bar"}# Вышеприведенное эквивалентно следующемуtmp=MyType.newtmp["foo"]="bar"tmp# Диапазоны1..10#=> Range(Int32, Int32)Range.new(1,10).class#=> Range(Int32, Int32)# Включающий и исключающий диапазоны(3..5).to_a#=> [3, 4, 5](3...5).to_a#=> [3, 4]# Проверка на вхождение в диапазон(1..8).includes?2#=> true# Кортежи# Неизменяемые последовательности фиксированного размера, содержащие,# как правило, элементы разных типов{1,"hello",'x'}.class#=> Tuple(Int32, String, Char)# Доступ к элементам осуществляется по индексуtuple={:key1,:key2}tuple[1]#=> :key2tuple[2]#=> syntax error : Index out of bound# Элементы кортежей можно попарно присвоить переменнымa,b,c={:a,'b',"c"}a#=> :ab#=> 'b'c#=> "c"# Процедуры# Указатели на функцию с необязательным содержимым (замыкание).# Обычно создаётся с помощью специального литерала ->proc=->(x:Int32){x.to_s}proc.class# Proc(Int32, String)# Или посредством метода .newProc(Int32,String).new{|x|x.to_s}# Вызываются посредством метода .callproc.call10#=> "10"# Управляющие операторыiftrue"if statement"elsiffalse"else-if, optional"else"else, also optional"endputs"if as a suffix"iftrue# if как часть выраженияa=if2>13else4enda#=> 3# Тернарный ifa=1>2?3:4#=> 4# Оператор выбораcmd="move"action=casecmdwhen"create""Creating..."when"copy""Copying..."when"move""Moving..."when"delete""Deleting..."endaction#=> "Moving..."# Циклыindex=0whileindex<=3puts"Index: #{index}"index+=1end# Index: 0# Index: 1# Index: 2# Index: 3index=0untilindex>3puts"Index: #{index}"index+=1end# Index: 0# Index: 1# Index: 2# Index: 3# Но лучше использовать each(1..3).eachdo|index|puts"Index: #{index}"end# Index: 1# Index: 2# Index: 3# Тип переменной зависит от типа выраженияifa<3a="hello"elsea=trueendtypeofa#=> (Bool | String)ifa&&b# здесь гарантируется, что и a, и b — не nilendifa.is_a?Stringa.class#=> Stringend# Методыdefdouble(x)x*2end# Методы (а также любые блоки) всегда возвращают значение последнего выраженияdouble(2)#=> 4# Скобки можно опускать, если вызов метода не вносит двусмысленностиdouble3#=> 6doubledouble3#=> 12defsum(x,y)x+yend# Параметры методов перечисляются через запятуюsum3,4#=> 7sumsum(3,4),5#=> 12# yield# У всех методов есть неявный необязательный параметр блока, который можно# вызвать ключевым словом yielddefsurroundputs'{'yieldputs'}'endsurround{puts"hello world"}# {# hello world# }# Методу можно передать блок# & — ссылка на переданный блокdefguests(&block)block.call"some_argument"end# Методу можно передать список параметров, доступ к ним будет как к массиву# Для этого используется оператор *defguests(*array)array.each{|guest|putsguest}end# Если метод возвращает массив, можно попарно присвоить значение каждого из его# элементов переменнымdeffoods["pancake","sandwich","quesadilla"]endbreakfast,lunch,dinner=foodsbreakfast#=> "pancake"dinner#=> "quesadilla"# По соглашению название методов, возвращающих булево значение, должно# оканчиваться вопросительным знаком5.even?# false5.odd?# true# Если название метода оканчивается восклицательным знаком, по соглашению это# означает, что метод делает что-то необратимое, например изменяет получателя.# Некоторые методы имеют две версии: "опасную" версию с !, которая что-то# меняет, и "безопасную", которая просто возвращает новое значениеcompany_name="Dunder Mifflin"company_name.gsub"Dunder","Donald"#=> "Donald Mifflin"company_name#=> "Dunder Mifflin"company_name.gsub!"Dunder","Donald"company_name#=> "Donald Mifflin"# Классы# Определяются с помощью ключевого слова classclassHuman# Переменная класса является общей для всех экземпляров этого класса@@species="H. sapiens"# Объявление типа переменной name экземпляра класса@name:String# Базовый конструктор# Значением первого параметра инициализируем переменную @name.# То же делаем и со вторым параметром — переменная @age. В случае, если мы# не передаём второй параметр, для инициализации @age будет взято значение# по умолчанию (в данном случае — 0)definitialize(@name,@age=0)end# Базовый метод установки значения переменнойdefname=(name)@name=nameend# Базовый метод получения значения переменнойdefname@nameend# Синтаксический сахар одновременно для двух методов вышеproperty:name# А также по отдельностиgetter:namesetter:name# Метод класса определяется ключевым словом self, чтобы его можно было# различить с методом экземпляра класса. Такой метод можно вызвать только# на уровне класса, а не экземпляра.defself.say(msg)putsmsgenddefspecies@@speciesendend# Создание экземпляра классаjim=Human.new("Jim Halpert")dwight=Human.new("Dwight K. Schrute")# Вызов методов экземпляра классаjim.species#=> "H. sapiens"jim.name#=> "Jim Halpert"jim.name="Jim Halpert II"#=> "Jim Halpert II"jim.name#=> "Jim Halpert II"dwight.species#=> "H. sapiens"dwight.name#=> "Dwight K. Schrute"# Вызов метода классаHuman.say("Hi")#=> выведет "Hi" и вернёт nil# Переменные экземпляра класса (@) видно только в пределах экземпляраclassTestClass@var="I'm an instance var"end# Переменные класса (@) видны как в экземплярах класса, так и в самом классеclassTestClass@@var="I'm a class var"end# Переменные с большой буквы — это константыVar="I'm a constant"Var="can't be updated"# Error: already initialized constant Var# Примеры# Базовый классclassHuman@@foo=0defself.foo@@fooenddefself.foo=(value)@@foo=valueendend# Класс-потомокclassWorker<HumanendHuman.foo#=> 0Worker.foo#=> 0Human.foo=2#=> 2Worker.foo#=> 0Worker.foo=3#=> 3Human.foo#=> 2Worker.foo#=> 3moduleModuleExampledeffoo"foo"endend# Подключение модуля в класс добавляет его методы в экземпляр класса# Расширение модуля добавляет его методы в сам классclassPersonincludeModuleExampleendclassBookextendModuleExampleendPerson.foo# => undefined method 'foo' for Person:ClassPerson.new.foo# => 'foo'Book.foo# => 'foo'Book.new.foo# => undefined method 'foo' for Book# Обработка исключений# Создание пользовательского типа исключенияclassMyException<Exceptionend# Ещё одногоclassMyAnotherException<Exception;endex=beginraiseMyException.newrescueex1:IndexError"ex1"rescueex2:MyException|MyAnotherException"ex2"rescueex3:Exception"ex3"rescueex4# без указания конкретного типа исключения будут "отлавливаться" все"ex4"endex#=> "ex2"