diff options
| -rw-r--r-- | ru-ru/crystal-ru.html.markdown | 584 | 
1 files changed, 584 insertions, 0 deletions
| diff --git a/ru-ru/crystal-ru.html.markdown b/ru-ru/crystal-ru.html.markdown new file mode 100644 index 00000000..87d12f23 --- /dev/null +++ b/ru-ru/crystal-ru.html.markdown @@ -0,0 +1,584 @@ +--- +language: crystal +filename: learncrystal-ru.cr +contributors: +    - ["Vitalii Elenhaupt", "http://veelenga.com"] +    - ["Arnaud Fernandés", "https://github.com/TechMagister/"] +translators: +    - ["Den Patin", "https://github.com/denpatin"] +lang: ru-ru +--- + +```crystal +# — так начинается комментарий + + +# Всё является объектом +nil.class  #=> Nil +100.class  #=> Int32 +true.class #=> Bool + +# Возвращают false только nil, false и пустые указатели +!nil   #=> true  : Bool +!false #=> true  : Bool +!0     #=> false : Bool + + +# Целые числа + +1.class #=> Int32 + +# Четыре типа целых чисел со знаком +1_i8.class  #=> Int8 +1_i16.class #=> Int16 +1_i32.class #=> Int32 +1_i64.class #=> Int64 + +# Четыре типа целых чисел без знака +1_u8.class  #=> UInt8 +1_u16.class #=> UInt16 +1_u32.class #=> UInt32 +1_u64.class #=> UInt64 + +2147483648.class          #=> Int64 +9223372036854775808.class #=> UInt64 + +# Двоичные числа +0b1101 #=> 13 : Int32 + +# Восьмеричные числа +0o123 #=> 83 : Int32 + +# Шестнадцатеричные числа +0xFE012D #=> 16646445 : Int32 +0xfe012d #=> 16646445 : Int32 + +# Числа с плавающей точкой + +1.0.class #=> Float64 + +# Два типа чисел с плавающей запятой +1.0_f32.class #=> Float32 +1_f32.class   #=> Float32 + +1e10.class    #=> Float64 +1.5e10.class  #=> Float64 +1.5e-7.class  #=> Float64 + + +# Символьные литералы + +'a'.class #=> Char + +# Восьмеричный код символа +'\101' #=> 'A' : Char + +# Код символа Unicode +'\u0041' #=> 'A' : Char + + +# Строки + +"s".class #=> String + +# Строки неизменяемы +s = "hello, "  #=> "hello, "        : String +s.object_id    #=> 134667712        : UInt64 +s += "Crystal" #=> "hello, Crystal" : String +s.object_id    #=> 142528472        : UInt64 + +# Поддерживается интерполяция строк +"sum = #{1 + 2}" #=> "sum = 3" : String + +# Поддерживается многострочность +"This is +   multiline string" + +# Строка с двойными кавычками +%(hello "world") #=> "hello \"world\"" + + +# Символы — константы без значения, определяемые только именем. Часто +# используются вместо часто используемых строк для лучшей производительности. +# На внутреннем уровне они представлены как Int32. + +:symbol.class #=> Symbol + +sentence = :question?     # :"question?" : Symbol + +sentence == :question?    #=> true  : Bool +sentence == :exclamation! #=> false : Bool +sentence == "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' +[] of Int32      #=> [] : Array(Int32) +Array(Int32).new #=> [] : Array(Int32) + +# Элементы внутри массива имеют свои индексы +array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] : Array(Int32) +array[0]                #=> 1               : Int32 +array[10]               # raises IndexError +array[-6]               # raises IndexError +array[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 #=> 6 +array     #=> [1, 2, 3, 4, 5] + +# Удаление элемента из начала массива +array.shift #=> 1 +array       #=> [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)).new +set << 1 +set << 2 +set << 3 + + +# Хэши + +{1 => 2, 3 => 4}.class   #=> Hash(Int32, Int32) +{1 => 2, 'a' => 3}.class #=> Hash(Int32 | Char, Int32) + +# При объявлении пустого хэша необходимо указать типы ключа и значения +{}                     # Syntax error +{} of Int32 => 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 и #[]= +class MyType +  def []=(key, value) +    puts "do stuff" +  end +end + +MyType{"foo" => "bar"} + +# Вышеприведенное эквивалентно следующему +tmp = MyType.new +tmp["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] #=> :key2 +tuple[2] #=> syntax error : Index out of bound + +# Элементы кортежей можно попарно присвоить переменным +a, b, c = {:a, 'b', "c"} +a #=> :a +b #=> 'b' +c #=> "c" + + +# Процедуры +# Указатели на функцию с необязательным содержимым (замыкание). +# Обычно создаётся с помощью специального литерала -> + +proc = ->(x : Int32) { x.to_s } +proc.class # Proc(Int32, String) +# Или посредством метода .new +Proc(Int32, String).new { |x| x.to_s } + +# Вызываются посредством метода .call +proc.call 10 #=> "10" + + +# Управляющие операторы + +if true +  "if statement" +elsif false +  "else-if, optional" +else +  "else, also optional" +end + +puts "if as a suffix" if true + +# if как часть выражения +a = if 2 > 1 +      3 +    else +      4 +    end + +a #=> 3 + +# Тернарный if +a = 1 > 2 ? 3 : 4 #=> 4 + +# Оператор выбора +cmd = "move" + +action = case cmd +         when "create" +           "Creating..." +         when "copy" +           "Copying..." +         when "move" +           "Moving..." +         when "delete" +           "Deleting..." +end + +action #=> "Moving..." + + +# Циклы + +index = 0 +while index <= 3 +  puts "Index: #{index}" +  index += 1 +end +# Index: 0 +# Index: 1 +# Index: 2 +# Index: 3 + +index = 0 +until index > 3 +  puts "Index: #{index}" +  index += 1 +end +# Index: 0 +# Index: 1 +# Index: 2 +# Index: 3 + +# Но лучше использовать each +(1..3).each do |index| +  puts "Index: #{index}" +end +# Index: 1 +# Index: 2 +# Index: 3 + +# Тип переменной зависит от типа выражения +if a < 3 +  a = "hello" +else +  a = true +end +typeof a #=> (Bool | String) + +if a && b +  # здесь гарантируется, что и a, и b — не nil +end + +if a.is_a? String +  a.class #=> String +end + + +# Методы + +def double(x) +  x * 2 +end + +# Методы (а также любые блоки) всегда возвращают значение последнего выражения +double(2) #=> 4 + +# Скобки можно опускать, если вызов метода не вносит двусмысленности +double 3 #=> 6 + +double double 3 #=> 12 + +def sum(x, y) +  x + y +end + +# Параметры методов перечисляются через запятую +sum 3, 4 #=> 7 + +sum sum(3, 4), 5 #=> 12 + + +# yield + +# У всех методов есть неявный необязательный параметр блока, который можно +# вызвать ключевым словом yield + +def surround +  puts '{' +  yield +  puts '}' +end + +surround { puts "hello world" } + +# { +# hello world +# } + +# Методу можно передать блок +# & — ссылка на переданный блок +def guests(&block) +  block.call "some_argument" +end + +# Методу можно передать список параметров, доступ к ним будет как к массиву +# Для этого используется оператор * +def guests(*array) +  array.each { |guest| puts guest } +end + +# Если метод возвращает массив, можно попарно присвоить значение каждого из его +# элементов переменным +def foods +    ["pancake", "sandwich", "quesadilla"] +end +breakfast, lunch, dinner = foods +breakfast #=> "pancake" +dinner    #=> "quesadilla" + +# По соглашению название методов, возвращающих булево значение, должно +# оканчиваться вопросительным знаком +5.even? # false +5.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" + + +# Классы +# Определяются с помощью ключевого слова class + +class Human + +  # Переменная класса является общей для всех экземпляров этого класса +  @@species = "H. sapiens" + +  # Объявление типа переменной name экземпляра класса +  @name : String + +  # Базовый конструктор +  # Значением первого параметра инициализируем переменную @name. +  # То же делаем и со вторым параметром — переменная @age. В случае, если мы +  # не передаём второй параметр, для инициализации @age будет взято значение +  # по умолчанию (в данном случае — 0) +  def initialize(@name, @age = 0) +  end + +  # Базовый метод установки значения переменной +  def name=(name) +    @name = name +  end + +  # Базовый метод получения значения переменной +  def name +    @name +  end + +  # Синтаксический сахар одновременно для двух методов выше +  property :name + +  # А также по отдельности +  getter :name +  setter :name + +  # Метод класса определяется ключевым словом self, чтобы его можно было +  # различить с методом экземпляра класса. Такой метод можно вызвать только +  # на уровне класса, а не экземпляра. +  def self.say(msg) +    puts msg +  end + +  def species +    @@species +  end +end + + +# Создание экземпляра класса +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 + +# Переменные экземпляра класса (@) видно только в пределах экземпляра +class TestClass +  @var = "I'm an instance var" +end + +# Переменные класса (@) видны как в экземплярах класса, так и в самом классе +class TestClass +  @@var = "I'm a class var" +end + +# Переменные с большой буквы — это константы +Var = "I'm a constant" +Var = "can't be updated" # Error: already initialized constant Var + +# Примеры + +# Базовый класс +class Human +  @@foo = 0 + +  def self.foo +    @@foo +  end + +  def self.foo=(value) +    @@foo = value +  end +end + +# Класс-потомок +class Worker < Human +end + +Human.foo   #=> 0 +Worker.foo  #=> 0 + +Human.foo = 2 #=> 2 +Worker.foo    #=> 0 + +Worker.foo = 3 #=> 3 +Human.foo   #=> 2 +Worker.foo  #=> 3 + +module ModuleExample +  def foo +    "foo" +  end +end + +# Подключение модуля в класс добавляет его методы в экземпляр класса +# Расширение модуля добавляет его методы в сам класс + +class Person +  include ModuleExample +end + +class Book +  extend ModuleExample +end + +Person.foo     # => undefined method 'foo' for Person:Class +Person.new.foo # => 'foo' +Book.foo       # => 'foo' +Book.new.foo   # => undefined method 'foo' for Book + + +# Обработка исключений + +# Создание пользовательского типа исключения +class MyException < Exception +end + +# Ещё одного +class MyAnotherException < Exception; end + +ex = begin +   raise MyException.new +rescue ex1 : IndexError +  "ex1" +rescue ex2 : MyException | MyAnotherException +  "ex2" +rescue ex3 : Exception +  "ex3" +rescue ex4 # без указания конкретного типа исключения будут "отлавливаться" все +  "ex4" +end + +ex #=> "ex2" + +``` + +## Дополнительная информация + +### На русском + +- [Официальная документация](http://ru.crystal-lang.org/docs/) + +### На английском + +- [Official Documentation](http://crystal-lang.org/) | 
