Подтвердить что ты не робот

Рубиновый многострочный блок не заканчивается

Я новичок в Ruby, поэтому мне жаль спрашивать что-то настолько простое, но что-то не так с этим кодом -

3.upto(9) {
  print "Hello"
  puts " World"
}

или

3.upto(9) { |n|
  print "Hello "
  puts n
}

Он работает достаточно хорошо, но большинство примеров кода, которые я вижу, используют синтаксис

3.upto(9) do |n|
  print "Hello "
  puts n
end

Это просто соглашение использовать только фигурные скобки для отдельных операторов? Исходя из C/С#, первый кажется мне более естественным, но когда в Риме!

4b9b3361

Ответ 1

Существует тонкая разница между двумя синтаксисами. { } имеют более высокий приоритет, чем do ... end. Таким образом, следующее будет проходить bar и блок к методу foo:

foo bar do ... end

в то время как следующее передает блок bar, а результат этого - foo:

foo bar { ... }

Итак, ваши примеры будут действовать одинаково. Однако, если вы оставили круглые скобки:

> 3.upto 9 { 
  puts "Hi" 
}
SyntaxError: compile error
(irb):82: syntax error, unexpected '{', expecting $end
3.upto 9 { 
          ^
    from (irb):82
    from :0

> 3.upto 9 do 
    puts "Hi" 
  end
Hi
Hi
Hi
Hi
Hi
Hi
Hi
=> 3

Итак, { } с большей вероятностью поймают вас, если вы оставите скобки в Ruby, что довольно часто; по этой причине, и поскольку условия Ruby и другие конструкторы управления используют end как разделитель, люди обычно используют do ... end для многострочных блоков кода, которые находятся в конце инструкции.

Однако { } часто используется в местах, где do ... end будет громоздким, например, если вы объединяете несколько методов вместе, которые принимают блоки. Это может позволить вам написать короткие, однострочные маленькие блоки, которые могут использоваться как часть цепочки методов.

> [1,2,3].sort{|x,y| y<=>x}.map{|x| x+1}
=> [4, 3, 2]

Вот пример, иллюстрирующий эту разницу:

def foo arg
  if block_given?
    puts "Block given to foo"
    yield arg
  else
    puts "No block given to foo"
    arg
  end
end


def bar
  if block_given?
    puts "Block given to bar"
    yield "Yielded from bar"
  else
    puts "No block given to bar"
  end
  "Returned from bar"
end

irb(main):077:0> foo bar { |arg| puts arg }
Block given to bar
Yielded from bar
No block given to foo
=> "Returned from bar"
irb(main):078:0> foo bar do |arg| puts arg end
No block given to bar
Block given to foo
Returned from bar
=> nil

Ответ 2

Это просто соглашение.

Ответ 3

Там seamless. Из README:

Python позволяет вам сигнализировать о конце кода с отступом. Ruby страдает от чрезвычайно подробного и утомительного терминатора блока, "end". Подобно тому, как у Lisps есть десятки близких парен, файлы Ruby, которые используют модули и классы, в конечном итоге заканчиваются множеством "концов", которые просто не нужны.

Напишите файл Ruby, но пропустите все "концы". Выстройте свои блоки кода, как в Python. Затем просто назовите его "your_file.rbe", попросите "бесшовную" и потребуйте "ваш_файл". Бесшовные делает все остальное.

Должно ли это когда-либо увидеть широкое использование? Я не знаю. Но это довольно весело!