2013-09-03 4 views
6

Следующий код использует флип-флоп-оператора.Почему оператор Flip-Flop включает второе условие?

(1..10).each {|x| print "#{x}," if x==3..x==5 } 

Почему результаты 3,4,5?

Я думаю, это должно быть 3,4.

Как упоминалось в учебнике, это выражение становится истинным, когда x == 3, и продолжает оставаться истинным до x == 5. Как можно было напечатать «5», если оно будет ошибочным? Может ли кто-нибудь прояснить это для меня?

+0

ссылку на документацию пожалуйста. –

+3

Вы ответили на свой вопрос. 'и продолжайте оставаться до тех пор, пока x == 5' – MurifoX

+0

, но когда x станет 5, это неверно? как можно было напечатать тогда? – bean

ответ

0

Вы ищете эксклюзивный ассортимент? Вы можете использовать три точки и метод cover?.

(1..10).each { |x| print "#{x}," if (3...5).cover?(x) } 

Причина печатает 3,4,5, в вашем примере, потому что это говорит, что если х находится в диапазоне от 3 до 5 напечатать.

0

Чтобы прояснить комментарий @MurifoX, триггер верен до x==5 и, таким образом, имеет значение true, когда x==5, но является ложным каждый раз, когда выражение оценивается после этого. Таким образом, вы все еще видите, что 5 печатаются.

+0

спасибо, это разумно. – bean

4

Важным звеном, от «Рубина» Язык программирования является:

4.6.9.1 Boolean flip-flops

Когда .. и ... операторы используются в условном, например, если заявление, или в цикле, таком как цикл while (подробнее см. Главу 5 об условных обозначениях и циклах), они не создают объекты Range. Вместо этого они создают особый вид выражения Boolean , называемого триггером. Выражение флип-флопа оценивается как истинное или ложное, так же как и выражения сравнения и равенства. Необычайно необычная вещь о выражении флип-флопа , однако, заключается в том, что его значение зависит от значения предыдущих оценок - . Это означает, что выражение флип-флопа связано с ним; он должен запомнить информацию о предыдущих оценках. Поскольку он имеет состояние, вы бы предположили, что флип-флоп будет каким-то объектом. Но это не так - это выражение Ruby, а интерпретатор Ruby хранит состояние (просто одно логическое значение), которое требуется во внутреннем анализируемом представлении выражения.

Учитывая этот фон, рассмотрите триггер в следующем коде. Обратите внимание: первый .. в коде создается объект Range. Второй создает триггер выражения:

(1..10).each {|x| print x if x==3..x==5 } 

триггер состоит из двух логических выражений соединено с .. оператором, в контексте условного или петли. Выражение флип-флопа является ложным, пока и до тех пор, пока выражение lefthand не примет значение true. Как только это выражение стало истинным, выражение ex- «переворачивается» в постоянное истинное состояние. Он остается в этом состоянии, а последующие оценки возвращают значение true, пока правое выражение не примет значение true. Когда происходит это , триггер «проваливается» обратно в постоянное ложное состояние.Последующие оценки выражения возвращают false, пока выражение lefthand снова не станет истинным. В примере кода триггер оценивается несколько раз, для значений х от 1 до 10. Он начинается в ложном состоянии и вычисляется как false, когда x равно 1 и 2. Когда x == 3, триггер переворачивается в true и возвращает true. Он продолжает возвращать true, когда x равен 4 и 5. Если x == 5, триггер возвращается к false и возвращает false для оставшихся значений x. В результате этот код печатает 345.

3

.. или триггер наследуется от Perl, который получил его от AWK и sed в * nix. Он очень мощный, но в вашем конкретном использовании он довольно неясен и не является хорошим выбором для логики, которую вы хотите, особенно в Ruby. Вместо того, чтобы использовать:

(1..10).each {|x| puts x if (3..5) === x } 

Какие выходы:

3 
4 
5 

Тем не менее, это очень мощный, когда вам нужно извлечь диапазон строк из файла:

File.foreach('/usr/share/dict/propernames') { |li| puts li if ($. == 5 .. $. == 7) } 

который выводит:

Agatha 
Ahmed 
Ahmet 

Perl allow s еще более тонкое выражение, использующее только номера строк текущей строки (AKA $.), но Ruby не поддерживает это.

Там также возможность использования регулярных выражений, которые ведут себя так же, как и предыдущие сравнения:

File.foreach('/usr/share/dict/propernames') { |li| puts li if (li[/^Wa/] .. li[/^We/]) } 

который выводит:

Wade 
Walt 
Walter 
Warren 
Wayne 
Wendell 

Поскольку регулярное выражение работы, можно создать сложный рисунок на извлекать строки из файла на основе совпадений. В качестве первого, затем запускается второй шаблон, линии. Если позже в файле другая строка запускает первый шаблон, то захват будет снова выполняться до тех пор, пока не будет найден второй шаблон. Это удивительно мощное:

File.foreach('/usr/share/dict/propernames') { |li| puts li if (
    li[/^Am/] .. li[/^An/] or 
    li[/^Wa/] .. li[/^We/] 
) 
} 

Каких выходы:

Amanda 
Amarth 
Amedeo 
Ami 
Amigo 
Amir 
Amos 
Amy 
Anatole 
Wade 
Walt 
Walter 
Warren 
Wayne 
Wendell 

Или поочередно, для наших неясных кодов говорящих друзей:

File.foreach('/usr/share/dict/propernames') { |li| puts li if (li[/^(?:Am|Wa)/] .. li[/^(?:An|We)/]) } 
1

Я нахожу кусок кода, чтобы показать, как триггер работает (только в той же книге, где появляется этот кусок кода, надеюсь, что это поможет тем, у кого такой же вопрос, как я)

$state = false # Global storage for flip-flop state 
    def flipflop(x) # Test value of x against flip-flop 
     if !$state # If saved state is false 
      result = (x == 3) # Result is value of lefthand operand 
      if result # If that result is true 
       $state = !(x == 5) # Then saved state is not of the righthand operand 
      end 
      result # Return result 
     else # Otherwise, if saved state is true 
      $state = !(x == 5) # Then save the inverse of the righthand operand 
      true # And return true without testing lefthand 
     end 
    end 
0

Выражение триггер принимает значение истина или ложь, так же, как делать сравнения и равенства выражений. Необычайно необычная вещь о флип-флопе, однако, заключается в том, что ее значение зависит от значения предыдущих оценок. Это означает, что выражение флип-флопа связано с ним; он должен помнить информацию о предыдущих оценках. Поскольку он имеет состояние, вы бы предположили, что флип-флоп будет каким-то объектом.Но это не так - это выражение Ruby, а интерпретатор Ruby хранит состояние (просто одно логическое значение), которое требуется во внутреннем анализируемом представлении выражения. Исходя из этого, рассмотрите триггер в следующем коде. Обратите внимание, что первый «..» в коде создает объект Range. Второй создает выражение триггера:

(1..10).each {|x| print x if x==3..x==5 } 

триггер состоит из двух логических выражений, соединенных с .. оператором, в контексте условного или петли. Выражение флип-флопа является ложным, пока и до тех пор, пока выражение lefthand не примет значение true. Как только это выражение стало истинным, выражение «переворачивается» в постоянное истинное состояние. Он остается в этом состоянии, а последующие оценки возвращают значение true, пока правое выражение не примет значение true. Когда происходит это , триггер «проваливается» обратно в постоянное ложное состояние. Последующие оценки выражения возвращают false, пока выражение lefthand снова не станет истинным. В примере кода триггер оценивается несколько раз, для значений х от 1 до 10. Он начинается в ложном состоянии и оценивается как false, когда x равно 1 и 2. Когда x == 3, триггер переключается на true и возвращает true. Он продолжает возвращаться, когда x равно 4 и 5. Однако при x == 5 триггер возвращается к false и возвращает false для оставшихся значений x. В результате этот код печатает 345.