crystal.md

Личный сайт Go-разработчика из Казани

1# — так начинается комментарий 2 3 4# Всё является объектом 5nil.class #=> Nil 6100.class #=> Int32 7true.class #=> Bool 8 9# Возвращают false только nil, false и пустые указатели 10!nil #=> true : Bool 11!false #=> true : Bool 12!0 #=> false : Bool 13 14 15# Целые числа 16 171.class #=> Int32 18 19# Четыре типа целых чисел со знаком 201_i8.class #=> Int8 211_i16.class #=> Int16 221_i32.class #=> Int32 231_i64.class #=> Int64 24 25# Четыре типа целых чисел без знака 261_u8.class #=> UInt8 271_u16.class #=> UInt16 281_u32.class #=> UInt32 291_u64.class #=> UInt64 30 312147483648.class #=> Int64 329223372036854775808.class #=> UInt64 33 34# Двоичные числа 350b1101 #=> 13 : Int32 36 37# Восьмеричные числа 380o123 #=> 83 : Int32 39 40# Шестнадцатеричные числа 410xFE012D #=> 16646445 : Int32 420xfe012d #=> 16646445 : Int32 43 44# Числа с плавающей точкой 45 461.0.class #=> Float64 47 48# Два типа чисел с плавающей запятой 491.0_f32.class #=> Float32 501_f32.class #=> Float32 51 521e10.class #=> Float64 531.5e10.class #=> Float64 541.5e-7.class #=> Float64 55 56 57# Символьные литералы 58 59'a'.class #=> Char 60 61# Восьмеричный код символа 62'\101' #=> 'A' : Char 63 64# Код символа Unicode 65'\u0041' #=> 'A' : Char 66 67 68# Строки 69 70"s".class #=> String 71 72# Строки неизменяемы 73s = "hello, " #=> "hello, " : String 74s.object_id #=> 134667712 : UInt64 75s += "Crystal" #=> "hello, Crystal" : String 76s.object_id #=> 142528472 : UInt64 77 78# Поддерживается интерполяция строк 79"sum = #{1 + 2}" #=> "sum = 3" : String 80 81# Поддерживается многострочность 82"This is 83 multiline string" 84 85# Строка с двойными кавычками 86%(hello "world") #=> "hello \"world\"" 87 88 89# Символы — константы без значения, определяемые только именем. Часто 90# используются вместо часто используемых строк для лучшей производительности. 91# На внутреннем уровне они представлены как Int32. 92 93:symbol.class #=> Symbol 94 95sentence = :question? # :"question?" : Symbol 96 97sentence == :question? #=> true : Bool 98sentence == :exclamation! #=> false : Bool 99sentence == "question?" #=> false : Bool 100 101 102# Массивы 103 104[1, 2, 3].class #=> Array(Int32) 105[1, "hello", 'x'].class #=> Array(Int32 | String | Char) 106 107# При объявлении пустого массива необходимо указать тип его элементов 108[] # Syntax error: for empty arrays use '[] of ElementType' 109[] of Int32 #=> [] : Array(Int32) 110Array(Int32).new #=> [] : Array(Int32) 111 112# Элементы внутри массива имеют свои индексы 113array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] : Array(Int32) 114array[0] #=> 1 : Int32 115array[10] # raises IndexError 116array[-6] # raises IndexError 117array[10]? #=> nil : (Int32 | Nil) 118array[-6]? #=> nil : (Int32 | Nil) 119 120# Можно получать элементы по индексу с конца 121array[-1] #=> 5 122 123# С начала и с указанием размера итогового массива 124array[2, 3] #=> [3, 4, 5] 125 126# Или посредством указания диапазона 127array[1..3] #=> [2, 3, 4] 128 129# Добавление в массив 130array << 6 #=> [1, 2, 3, 4, 5, 6] 131 132# Удаление элемента из конца массива 133array.pop #=> 6 134array #=> [1, 2, 3, 4, 5] 135 136# Удаление элемента из начала массива 137array.shift #=> 1 138array #=> [2, 3, 4, 5] 139 140# Проверка на наличие элемента в массиве 141array.includes? 3 #=> true 142 143# Синтаксический сахар для массива строк и символов 144%w(one two three) #=> ["one", "two", "three"] : Array(String) 145%i(one two three) #=> [:one, :two, :three] : Array(Symbol) 146 147# Массивоподобный синтаксис используется и для других типов, только если для 148# них определены методы .new и #<< 149set = Set{1, 2, 3} #=> [1, 2, 3] 150set.class #=> Set(Int32) 151 152# Вышеприведенное эквивалентно следующему 153set = Set(typeof(1, 2, 3)).new 154set << 1 155set << 2 156set << 3 157 158 159# Хэши 160 161{1 => 2, 3 => 4}.class #=> Hash(Int32, Int32) 162{1 => 2, 'a' => 3}.class #=> Hash(Int32 | Char, Int32) 163 164# При объявлении пустого хэша необходимо указать типы ключа и значения 165{} # Syntax error 166{} of Int32 => Int32 # {} 167Hash(Int32, Int32).new # {} 168 169# Значения в хэше легко найти по ключу 170hash = {"color" => "green", "number" => 5} 171hash["color"] #=> "green" 172hash["no_such_key"] #=> Missing hash key: "no_such_key" (KeyError) 173hash["no_such_key"]? #=> nil 174 175# Проверка наличия ключа в хэше 176hash.has_key? "color" #=> true 177 178# Синтаксический сахар для символьных и строковых ключей 179{key1: 'a', key2: 'b'} # {:key1 => 'a', :key2 => 'b'} 180{"key1": 'a', "key2": 'b'} # {"key1" => 'a', "key2" => 'b'} 181 182# Хэшеподобный синтаксис используется и для других типов, только если для них 183# определены методы .new и #[]= 184class MyType 185 def []=(key, value) 186 puts "do stuff" 187 end 188end 189 190MyType{"foo" => "bar"} 191 192# Вышеприведенное эквивалентно следующему 193tmp = MyType.new 194tmp["foo"] = "bar" 195tmp 196 197 198# Диапазоны 199 2001..10 #=> Range(Int32, Int32) 201Range.new(1, 10).class #=> Range(Int32, Int32) 202 203# Включающий и исключающий диапазоны 204(3..5).to_a #=> [3, 4, 5] 205(3...5).to_a #=> [3, 4] 206 207# Проверка на вхождение в диапазон 208(1..8).includes? 2 #=> true 209 210 211# Кортежи 212# Неизменяемые последовательности фиксированного размера, содержащие, 213# как правило, элементы разных типов 214 215{1, "hello", 'x'}.class #=> Tuple(Int32, String, Char) 216 217# Доступ к элементам осуществляется по индексу 218tuple = {:key1, :key2} 219tuple[1] #=> :key2 220tuple[2] #=> syntax error : Index out of bound 221 222# Элементы кортежей можно попарно присвоить переменным 223a, b, c = {:a, 'b', "c"} 224a #=> :a 225b #=> 'b' 226c #=> "c" 227 228 229# Процедуры 230# Указатели на функцию с необязательным содержимым (замыкание). 231# Обычно создаётся с помощью специального литерала -> 232 233proc = ->(x : Int32) { x.to_s } 234proc.class # Proc(Int32, String) 235# Или посредством метода .new 236Proc(Int32, String).new { |x| x.to_s } 237 238# Вызываются посредством метода .call 239proc.call 10 #=> "10" 240 241 242# Управляющие операторы 243 244if true 245 "if statement" 246elsif false 247 "else-if, optional" 248else 249 "else, also optional" 250end 251 252puts "if as a suffix" if true 253 254# if как часть выражения 255a = if 2 > 1 256 3 257 else 258 4 259 end 260 261a #=> 3 262 263# Тернарный if 264a = 1 > 2 ? 3 : 4 #=> 4 265 266# Оператор выбора 267cmd = "move" 268 269action = case cmd 270 when "create" 271 "Creating..." 272 when "copy" 273 "Copying..." 274 when "move" 275 "Moving..." 276 when "delete" 277 "Deleting..." 278end 279 280action #=> "Moving..." 281 282 283# Циклы 284 285index = 0 286while index <= 3 287 puts "Index: #{index}" 288 index += 1 289end 290# Index: 0 291# Index: 1 292# Index: 2 293# Index: 3 294 295index = 0 296until index > 3 297 puts "Index: #{index}" 298 index += 1 299end 300# Index: 0 301# Index: 1 302# Index: 2 303# Index: 3 304 305# Но лучше использовать each 306(1..3).each do |index| 307 puts "Index: #{index}" 308end 309# Index: 1 310# Index: 2 311# Index: 3 312 313# Тип переменной зависит от типа выражения 314if a < 3 315 a = "hello" 316else 317 a = true 318end 319typeof a #=> (Bool | String) 320 321if a && b 322 # здесь гарантируется, что и a, и b — не nil 323end 324 325if a.is_a? String 326 a.class #=> String 327end 328 329 330# Методы 331 332def double(x) 333 x * 2 334end 335 336# Методы (а также любые блоки) всегда возвращают значение последнего выражения 337double(2) #=> 4 338 339# Скобки можно опускать, если вызов метода не вносит двусмысленности 340double 3 #=> 6 341 342double double 3 #=> 12 343 344def sum(x, y) 345 x + y 346end 347 348# Параметры методов перечисляются через запятую 349sum 3, 4 #=> 7 350 351sum sum(3, 4), 5 #=> 12 352 353 354# yield 355 356# У всех методов есть неявный необязательный параметр блока, который можно 357# вызвать ключевым словом yield 358 359def surround 360 puts '{' 361 yield 362 puts '}' 363end 364 365surround { puts "hello world" } 366 367# { 368# hello world 369# } 370 371# Методу можно передать блок 372# & — ссылка на переданный блок 373def guests(&block) 374 block.call "some_argument" 375end 376 377# Методу можно передать список параметров, доступ к ним будет как к массиву 378# Для этого используется оператор * 379def guests(*array) 380 array.each { |guest| puts guest } 381end 382 383# Если метод возвращает массив, можно попарно присвоить значение каждого из его 384# элементов переменным 385def foods 386 ["pancake", "sandwich", "quesadilla"] 387end 388breakfast, lunch, dinner = foods 389breakfast #=> "pancake" 390dinner #=> "quesadilla" 391 392# По соглашению название методов, возвращающих булево значение, должно 393# оканчиваться вопросительным знаком 3945.even? # false 3955.odd? # true 396 397# Если название метода оканчивается восклицательным знаком, по соглашению это 398# означает, что метод делает что-то необратимое, например изменяет получателя. 399# Некоторые методы имеют две версии: "опасную" версию с !, которая что-то 400# меняет, и "безопасную", которая просто возвращает новое значение 401company_name = "Dunder Mifflin" 402company_name.gsub "Dunder", "Donald" #=> "Donald Mifflin" 403company_name #=> "Dunder Mifflin" 404company_name.gsub! "Dunder", "Donald" 405company_name #=> "Donald Mifflin" 406 407 408# Классы 409# Определяются с помощью ключевого слова class 410 411class Human 412 413 # Переменная класса является общей для всех экземпляров этого класса 414 @@species = "H. sapiens" 415 416 # Объявление типа переменной name экземпляра класса 417 @name : String 418 419 # Базовый конструктор 420 # Значением первого параметра инициализируем переменную @name. 421 # То же делаем и со вторым параметром — переменная @age. В случае, если мы 422 # не передаём второй параметр, для инициализации @age будет взято значение 423 # по умолчанию (в данном случае — 0) 424 def initialize(@name, @age = 0) 425 end 426 427 # Базовый метод установки значения переменной 428 def name=(name) 429 @name = name 430 end 431 432 # Базовый метод получения значения переменной 433 def name 434 @name 435 end 436 437 # Синтаксический сахар одновременно для двух методов выше 438 property :name 439 440 # А также по отдельности 441 getter :name 442 setter :name 443 444 # Метод класса определяется ключевым словом self, чтобы его можно было 445 # различить с методом экземпляра класса. Такой метод можно вызвать только 446 # на уровне класса, а не экземпляра. 447 def self.say(msg) 448 puts msg 449 end 450 451 def species 452 @@species 453 end 454end 455 456 457# Создание экземпляра класса 458jim = Human.new("Jim Halpert") 459 460dwight = Human.new("Dwight K. Schrute") 461 462# Вызов методов экземпляра класса 463jim.species #=> "H. sapiens" 464jim.name #=> "Jim Halpert" 465jim.name = "Jim Halpert II" #=> "Jim Halpert II" 466jim.name #=> "Jim Halpert II" 467dwight.species #=> "H. sapiens" 468dwight.name #=> "Dwight K. Schrute" 469 470# Вызов метода класса 471Human.say("Hi") #=> выведет "Hi" и вернёт nil 472 473# Переменные экземпляра класса (@) видно только в пределах экземпляра 474class TestClass 475 @var = "I'm an instance var" 476end 477 478# Переменные класса (@) видны как в экземплярах класса, так и в самом классе 479class TestClass 480 @@var = "I'm a class var" 481end 482 483# Переменные с большой буквы — это константы 484Var = "I'm a constant" 485Var = "can't be updated" # Error: already initialized constant Var 486 487# Примеры 488 489# Базовый класс 490class Human 491 @@foo = 0 492 493 def self.foo 494 @@foo 495 end 496 497 def self.foo=(value) 498 @@foo = value 499 end 500end 501 502# Класс-потомок 503class Worker < Human 504end 505 506Human.foo #=> 0 507Worker.foo #=> 0 508 509Human.foo = 2 #=> 2 510Worker.foo #=> 0 511 512Worker.foo = 3 #=> 3 513Human.foo #=> 2 514Worker.foo #=> 3 515 516module ModuleExample 517 def foo 518 "foo" 519 end 520end 521 522# Подключение модуля в класс добавляет его методы в экземпляр класса 523# Расширение модуля добавляет его методы в сам класс 524 525class Person 526 include ModuleExample 527end 528 529class Book 530 extend ModuleExample 531end 532 533Person.foo # => undefined method 'foo' for Person:Class 534Person.new.foo # => 'foo' 535Book.foo # => 'foo' 536Book.new.foo # => undefined method 'foo' for Book 537 538 539# Обработка исключений 540 541# Создание пользовательского типа исключения 542class MyException < Exception 543end 544 545# Ещё одного 546class MyAnotherException < Exception; end 547 548ex = begin 549 raise MyException.new 550rescue ex1 : IndexError 551 "ex1" 552rescue ex2 : MyException | MyAnotherException 553 "ex2" 554rescue ex3 : Exception 555 "ex3" 556rescue ex4 # без указания конкретного типа исключения будут "отлавливаться" все 557 "ex4" 558end 559 560ex #=> "ex2"

Дополнительная информация

На русском

На английском