WedX - журнал о программировании и компьютерных науках

Почему оператор break в ruby ​​ведет себя иначе при использовании Proc.new v. Знака амперсанда?

Оператор разрыва для блоков (согласно определяется как "rel =" язык "nnoreming" = "rel ="

он заставляет блок вернуться к своему итератору, а итератор - к методу, который его вызвал.

Поэтому при запуске следующего кода возникает ошибка LocalJumpError.

def test
    puts "entering test method"
    proc = Proc.new { puts "entering proc"; break }
    proc.call # LocalJumpError: iterator has already returned
    puts "exiting test method"
end
test

Хотя следующий код не вызывает ошибку LocalJumpError. Что особенного в знаке амперсанда? Разве знак амперсанда не использует неявно Proc.new?

def iterator(&proc)
    puts "entering iterator"
    proc.call # invoke the proc
    puts "exiting iterator" # Never executed if the proc breaks
end

def test
    iterator { puts "entering proc"; break }
end
test

Другими словами, я читаю знак амперсанда как средство встраивания вызова Proc.new. На этом этапе поведение должно быть таким же, как и в первом фрагменте кода.

def iterator (p = Proc.new { puts "entering proc"; break})
...
end

Заявление об ограничении ответственности: я новичок в изучении языка (ruby 1.9.2), поэтому буду благодарен за ссылки и подробный синопсис.


  • Нет времени для правильного ответа, но все дело в области видимости, а не в том, что Proc или Lambda особенные. 17.01.2012
  • когда у вас будет время ... пожалуйста, посетите этот вопрос еще раз. Я был бы признателен за ваше понимание 17.01.2012
  • Вместо Proc.new попробуйте lambda. 17.01.2012
  • Это общий вопрос о языке; в реализации я бы использовал лямбду 17.01.2012

Ответы:


1

break возвращает блок и вызывающего блока. В следующем коде:

proc = Proc.new { break }

"Вызывающий" блок, который преобразуется в объект Proc, - это Proc.new. break должен вернуть вызывающий блок, но Proc.new уже вернулся.

В этом коде:

def iterator(&b); b.call; end
iterator { break }

Вызывающий блок - iterator, поэтому он возвращает iterator.

24.01.2012
  • понял ... это лучший ответ. Однако не все ли блоки преобразованы в действенный код через Proc.new? Следовательно, итератор (& b) не становится итератором (b = Proc.new b)? 25.01.2012
  • & и Proc.new - это не одно и то же. & является основным синтаксисом; Proc.new - это библиотечный метод. Вы можете написать свой собственный Proc.new вот так: class Proc; def self.new(&b); b; end; end. Но вы не можете реализовать свой собственный основной синтаксис (кроме взлома интерпретатора или использования препроцессора). 25.01.2012

  • 2

    Вот ответ.

    Амперсанд используется для преобразования процесса в блок, а блока в процесс.

    Я изменил пример, чтобы он относился к вашему случаю:

    def run_my_code(&my_code)
     puts 'before proc'
     my_code.call
     puts 'after proc'
    end
    run_my_code { puts "passing a block, accepting a proc"; break}
    => before proc
       passing a block, accepting a proc
    

    Как видите, он не дошел до 'after proc'

    def run_my_code
     yield
    end
    my_proc = Proc.new  { puts "passing a proc instead of block"; break}
    run_my_code &my_proc
    => passing a proc instead of block
       LocalJumpError: break from proc-closure
       from (pry):75:in `block in <main>'
    

    Во втором примере у вас есть результат процедуры, процедура прерывается с iterator и возвращается к функции test.

    def iterator(&proc)
      puts 'entering iterator'
      proc.call
      puts 'exiting iterator'
    end
    
    def test
      puts 'before test'
      iterator { puts 'entering proc'; break }
      puts 'after test'
    end
    
    =>before test
    entering iterator
    entering proc
    after test
    
    17.01.2012
  • Если у меня это правильно, в первом примере оператор break возвращается из Proc.new (как итератор) и из блока, в котором он заключен. Я задокументировал определение в начале вопроса, так как понял, почему первое не удалось. Но, если во втором примере знак амперсанда - это синтаксический сахар для Proc.new, то я не понимаю, почему он там не дает сбоев. 17.01.2012
  • Итак, если блок был преобразован в процесс, то разве оператор break не должен работать так же, как первый фрагмент кода? Я имею в виду, если мы в основном встраиваем Proc.new, почему это ведет себя иначе, чем Proc.new, который был в отдельной строке над вызовом метода? 18.01.2012
  • процедура отключается от итератора и возвращается к тестовой функции. если это правда, то следующее определение итератора не должно приводить к сбою, но срабатывает: def iterator (p = Proc.new {вводит процедуру ввода; break}). Все, о чем я могу думать, это то, что Proc.new - это итератор, а знак амперсанда не использует оператор yield для создания процедуры. 19.01.2012
  • Да, мое объяснение не соответствует действительности. Теперь я думаю, что это из-за ключевого слова break, а не из-за proc. Но не могу найти полное описание этого ключевого слова. 19.01.2012

  • 3

    Это связано с разницей между блоками, процедурами и лямбдами - и их соответствующими областями действия.

    В 2009 году я написал об этом сообщение, которое может вам пригодиться: https://www.leonardoborges.com/writings/2009/07/22/procs-lambdas-blocks-whats-the-difference/

    Надеюсь это поможет.

    17.01.2012
  • Сообщение было явно проницательным, но, учитывая, что я использую процесс в обоих случаях, я не уверен, почему Ruby пытается уделять особое внимание одному процессу над другим? 17.01.2012
  • Это связано с объяснением ключевого слова return в сообщении. break, например return, в этом случае означает разрыв с вызывающим методом, в данном случае test. Однако вы не можете прервать тест, поскольку вы можете проверить, поставив паузу сразу после Proc.new {...}. Это отличается от вашего второго фрагмента, поскольку он возвращается из вызывающего метода, в данном случае итератора, возвращая управление новой версии теста. 17.01.2012
  • Итак, если тест был заключен в метод под названием test_test, оператор break в Proc.new не должен завершиться ошибкой? Вот как я читаю блок преобразования def iterator (& proc); #implicity call proc = Proc.new {proc}; ... end В этом случае должна произойти ошибка LocalJumpError, как и в случае с test. 17.01.2012
  • он вызывает это неявно, но не в iterator(&proc). Метод получает переданный Proc, а не создает его встроенным. 17.01.2012
  • тогда почему следующее не работает def iterator (proc) ... end iterator Proc.new {помещает ввод proc; ломать } 17.01.2012
  • Я хочу сказать, что если Proc передается итератору, он должен вести себя так же, как если бы кто-то вызвал Proc.new, если & не получил особых привилегий 17.01.2012
  • @ Салман, посмотри на ответ, который я только что отправил. Это объясняет, почему iterator(&Proc.new { break }) отличается от iterator { break }. 25.01.2012
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]