Какое лучшее объяснение для блоков Ruby, которые вы можете использовать?Лучшее объяснение блоков Ruby?
Как код использования, так и код, который может принимать блок?
Какое лучшее объяснение для блоков Ruby, которые вы можете использовать?Лучшее объяснение блоков Ruby?
Как код использования, так и код, который может принимать блок?
Книга "Programming Ruby" имеет отличное explanation of blocks and using them.
В 1.9+, список параметров передается в блок стал более сложным, что позволяет локальные переменные должны быть определены:
do |a,b;c,d|
some_stuff
end
;c,d
объявить два новых локальных переменных внутри блока, которые не получают значения из вызываемой подпрограммой yield
. Ruby 1.9+ гарантирует, что, если бы переменные существовали вне блока, они не будут топтаны одноименными переменными внутри блока. Это новое поведение; 1.8 будет топать на них.
def blah
yield 1,2,3,4
end
c = 'foo'
d = 'bar'
blah { |a, *b; c,d|
c = 'hello'
d = 'world'
puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}", "d: #{d}"
}
puts c, d
# >> a: 1
# >> b: 2,3,4
# >> c: hello
# >> d: world
# >> foo
# >> bar
Там же «знак» оператор *
, который работает в списке параметров:
do |a,*b|
some_stuff
end
присвоит первый из нескольких значений «а», а все остальные будут захвачены в «b», который будет обрабатываться как массив. *
может быть переменной a
:
do |*a,b|
some_stuff
end
бы захватить все прошло в переменных, за исключением последнего, который будет принят в b
. И, так же, как два предыдущих:
do |a,*b,c|
some_stuff
end
бы присвоить первое значение a
, последнее значение c
и все/любые промежуточные значения в b
.
Я думаю, что это довольно мощный и гладкий.
Например:
def blah
yield 1,2,3,4
end
blah { |a, *b| puts "a: #{a}", "b: #{b.join(',')}" }
# >> a: 1
# >> b: 2,3,4
blah { |*a, b| puts "a: #{a.join(',')}", "b: #{b}" }
# >> a: 1,2,3
# >> b: 4
blah { |a, *b, c| puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}" }
# >> a: 1
# >> b: 2,3
# >> c: 4
От Why's (poignant) guide to ruby:
Любой код в фигурные скобки является блока.
2.times { print "Yes, I've used chunky bacon in my examples, but never again!" }
является примером.С помощью блоков вы можете сгруппировать набор команд , чтобы они могли передавать вашу программу по адресу . В фигурных скобках видны краб-клещи, которые выхватили код и держат его вместе. Когда вы видите эти два клеща, помните , что код внутри был нажат в один блок.Это как один из этих маленьких Hello Kitty коробков они продают в торговом центре, который фаршированный крошечных карандашей и микроскопической бумагой, все ютятся в блестящем прозрачный корпус, который может быть скрытой в вашей ладони для тайных стационарных операций. За исключением того, что блоки не требуют так много щуриться. Кудрявые фигурные скобки также можно продавать для слов do и end, что приятно, если ваш блок длиннее одной строки.
loop do
print "Much better."
print "Ah. More space!"
print "My back was killin' me in those crab pincers."
end
Блок аргументы являются набор переменных, окруженных трубы символов, разделенных запятыми.
|x|, |x,y|, and |up, down, all_around| are examples.
Блок аргументы используются в начале блока.
{ |x,y| x + y }
В приведенном выше примере, | х, у | являются аргументами. После аргументов у нас есть немного кода. Выражение x + y объединяет два аргумента. I нравится думать о символах трубы как представляющий туннель. Они дают внешний вид желоба, который сбрасывает переменные . (А х идет вниз орлиный орел, а y аккуратно пересекает ее ноги.) Этот желоб действует как проход между блоками и окружающий мир . Переменные прошли через этот желоб (или туннель) в блок.
«Любой код, окруженный фигурными фигурными скобками, является блоком», если только это ** хэш **. – Meltemi
Вы не объясните, как вернутся эти примеры. Я не понимаю. –
Прошу быть репетитором! Спасибо, что объяснили это таким простым и понятным образом. – Benjamints
Блоки - это способ группировки кода в Ruby. Существует два способа записи блоков. Один использует оператор do..end, а другой окружает код в фигурных скобках: {}. Блоки считаются объектами на языке программирования Ruby, и по умолчанию все функции принимают неявный блок-аргумент.
Вот два примера блоков, которые делают то же самое:
2.times { puts 'hi' } 2.times do puts 'hi' end
Блоки могут получить списки разделенных запятыми аргументов внутри вертикальных столбиков ||. Например:
[1,2].map{ |n| n+2 } # [3, 4]
блоков (в рубин 1.9.2) можно явно иметь локальные переменные:
x = 'hello' 2.times do |;x| x = 'world' puts x end => world => world
Локальные переменные могут быть объединены с параметрами:
[1,2].map{ |n;x| n+2 }
Все функции могут получить аргумент блока по умолчанию:
def twice yield yield end twice { puts 'hello' } => hello => hello
В чем разница между do..end и {} блоками? По соглашению {} блоки находятся на одной строке и делают ..концевые блоки охватывают несколько строк, поскольку каждый из них легче читать таким образом. Основное различие связано с старшинства, хотя:
array = [1,2] puts array.map{ |n| n*10 } # puts (array.map{ |n| n*10 }) => 10 => 20 puts array.map do |n| n*10 end # (puts array.map) do |n| n*10 end => <Enumerator:0x00000100862670>
Блоки легкие литералы для анонимных процедур первого класса с некоторыми раздражающими ограничениями. Они работают так же, как в Ruby, так как они работают в значительной степени любой другой язык программирования, по модулю выше упомянутых ограничений, которые:
Хороший ответ, но отношение к объектам Proc кажется существенным, нет? – maerics
@maerics Существенный для исчерпывающего ресурса на блоках? Да. Существенное для объяснения блоков (которое я интерпретирую как введение в них для новичков)? Определенно нет, ИМО. – Phrogz
Спасибо. Ваш единственный ответ, который помог мне понять, почему '{puts" hello "}' не работает. Не разрешено вообще? Это странно. –
Я предлагаю мое собственное объяснение от this answer, слегка модифицирован:
«Блоки» в Ruby, не то же самые, как общие термины программирования " кодовый блок "o r "блок кода".
Притворитесь на мгновение, что следующий (недействительный) Рубиновый код на самом деле работал:
def add10(n)
puts "#{n} + 10 = #{n+10}"
end
def do_something_with_digits(method)
1.upto(9) do |i|
method(i)
end
end
do_something_with_digits(add10)
#=> "1 + 10 = 11"
#=> "2 + 10 = 12"
...
#=> "9 + 10 = 19"
Хотя этот код является недействительным, его намерение, минуя некоторый код к способу и имеющему, что метод выполнения кода, является возможно в Ruby различными способами. Одним из таких способов является «Блоки».
Блок в Ruby очень, очень похож на метод: он может принимать некоторые аргументы и запускать код для них. Всякий раз, когда вы видите foo{ |x,y,z| ... }
или foo do |x,y,z| ... end
, это блоки, которые принимают три параметра и запускают на них ...
. (Вы даже можете увидеть, что метод upto
выше передается в блок.)
Поскольку блоки являются особой частью синтаксиса Ruby, каждый метод имеет право передать блок. Использует ли метод блок до метода. Например:
def say_hi(name)
puts "Hi, #{name}!"
end
say_hi("Mom") do
puts "YOU SUCK!"
end
#=> Hi, Mom!
выше метод передается в блок, который готов выдать оскорбление, но так как метод не вызывает блок, только хорошо печатается сообщение. Вот как мы называем блок из метода:
def say_hi(name)
puts "Hi, #{name}!"
if block_given?
yield(name)
end
end
say_hi("Mridang") do |str|
puts "Your name has #{str.length} letters."
end
#=> Hi, Mridang!
#=> Your name has 7 letters.
Мы используем block_given?
, чтобы увидеть, был ли принят блок вместе или нет. В этом случае мы передали аргумент обратно в блок; это зависит от вашего метода, чтобы решить, что перейти к блоку. Например:
def say_hi(name)
puts "Hi, #{name}!"
yield(name, name.reverse) if block_given?
end
say_hi("Mridang"){ |str1, str2| puts "Is your name #{str1} or #{str2}?" }
#=> Hi, Mridang!
#=> Is your name Mridang or gnadirM?
Это просто соглашение (и хороший один и один вы хотите поддержать) для некоторых классов, чтобы передать экземпляр только что созданный блок.
Это не исчерпывающий ответ, поскольку он не охватывает блокирование блоков в качестве аргументов, как они обрабатывают arity, un-splatting в параметрах блока и т. Д., Но намереваются служить в качестве введения Blocks-Are-Lambdas.
Рубиновые блоки - это способ создания Proc
objects, которые представляют код, который может использоваться другим кодом.Объектами Proc являются команды между фигурными фигурными скобками {}
(или do...end
фразы для многострочных блоков, которые имеют более низкий приоритет, чем фигурные скобки), которые могут необязательно принимать аргументы и возвращать значения (например, {|x,y| x+y}
). Procs являются first-class objects и могут быть построены явно или достигается неявно, как метод псевдо-аргументов:
Строительство в качестве Proc объекта (или используя lambda
ключевое слово):
add1 = Proc.new {|x| x+1} # Returns its argument plus one.
add1.call(1) # => 2
Зачет как способ псевдо аргумент, либо явно используя специальный оператор синтаксиса синтаксиса последнего аргумента &
, либо неявно используя пару block_given?
/yield
:
def twice_do(&proc) # "proc" is the block given to a call of this method.
2.times { proc.call() } if proc
end
twice_do { puts "OK" } # Prints "OK" twice on separate lines.
def thrice_do() # if a block is given it can be called with "yield".
3.times { yield } if block_given?
end
thrice_do { puts "OK" } # Prints "OK" thrice on separate lines.
Вторая форма обычно используется для Visitor patterns; данные могут быть переданы аргументам специального блока в качестве аргументов методам call
или yield
.
Скобки имеют высокий приоритет; 'do' имеет низкий приоритет. Если вызов метода имеет параметры, которые не заключены в круглые скобки, форма скобки блока будет привязываться к последнему параметру, а не к общему вызову. Форма 'do' будет привязана к вызову. – Green
Почему downvote? – maerics
английский язык, пожалуйста! ...... «Блоки Ruby - это синтаксические литералы для объектов Proc ....» - если люди не знают, что такое блок, я предполагаю, что они не будут знать, что такое «синтаксические литералы для объектов Proc» означает либо , попробуйте объяснить, как если бы читателям было 5 лет. – BKSpurgeon
Для кого подходит к этому вопросу с C# фоне (или других LANGS на самом деле), это может помочь:
Рубиновые блоки, как лямбда-выражений и анонимных методов в C#. Это то, что C# вызывает делегатов (и Ruby вызывает Procs), то есть они суть функции, которые могут передаваться как значения. В Ruby и C# они также могут вести себя как замыкания.
Ruby: { |x| x + 1 }
C#: x => x + 1
Ruby: { |name| puts "Hello there #{name}" }
C#: name => { Console.WriteLine("Hello there {0}", name); }
Оба C# и Руби предлагают альтернативные способы, чтобы написать пример выше.
Рубин:
do |name|
puts "Hello there #{name}"
end
C#
delegate(string name)
{
Console.WriteLine("Hello there {0}", name);
}
В обоих Рубин и C#, несколько операторов разрешено, В Ruby, второй синтаксис выше для этого требуется.
Эти концепции доступны на многих других языках, на которые повлияли идеи функционального программирования.
Вы ищете введение в концепцию блоков или исчерпывающую ссылку на них? – Phrogz
Или вы просто троллитесь за репутацией, задавая вопросы, на которые вам не нужны ответы, не намерены принимать и не намерены даже участвовать в обсуждении? Посмотрим, если вы ответите. – Phrogz
Это полезная тема: http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ – Lucio