stringtranslate.com

Условное (компьютерное программирование)

Блок-схема «если-то-иначе»
Вложенная блок- схема if-then-else

В информатике условные выражения ( то есть условные операторы , условные выражения и условные конструкции ) — это команды языка программирования для обработки решений. В частности, условные выражения выполняют различные вычисления или действия в зависимости от того, какое значение имеет логическое условие, определенное программистом : истинное или ложное. С точки зрения потока управления , решение всегда достигается путем выборочного изменения потока управления на основе некоторого условия (кроме случая предсказания ветвления ). Хотя динамическая диспетчеризация обычно не классифицируется как условная конструкция, это еще один способ выбора между альтернативами во время выполнения . Условные операторы — это контрольные точки в программе, определяющие поведение в зависимости от ситуации.

Терминология

В императивных языках программирования обычно используется термин «условное выражение », тогда как в функциональном программировании предпочтительны термины «условное выражение » или «условная конструкция», поскольку все эти термины имеют разные значения.

Если-то(-иначе)

Эта if–thenконструкция (иногда называемая if–then–else) распространена во многих языках программирования. Хотя синтаксис варьируется от языка к языку, базовая структура (в форме псевдокода ) выглядит следующим образом:

Если (логическое условие) Тогда (последующий)Еще (альтернатива)Конец, если

Например:

Если запас=0 Тогда сообщение = заказать новый товарЕще сообщение= есть в наличииКонец, если

В приведенном выше примере кода часть, представленная (логическим условием), представляет собой условное выражение , имеющее внутреннее значение (например, оно может быть заменено любым из значений Trueили False), но не имеющее внутреннего значения. Напротив, комбинация этого выражения, Ifи, Thenокружающего его, и последующего, следующего за ним, составляют условное высказывание , имеющее внутреннее значение (например, выражающее связное логическое правило), но не имеющее внутренней ценности.

Когда интерпретатор находит If, он ожидает логическое условие – например, x > 0, что означает, что «переменная x содержит число, большее нуля» – и оценивает это условие. Если условие равно , выполняются trueинструкции, следующие за . thenВ противном случае выполнение продолжается в следующей ветке — либо в else блоке (что обычно необязательно), либо, если ветки нет else, то после end If.

После выполнения любой из ветвей управление возвращается в точку после end If.

История и развитие

В ранних языках программирования, особенно в некоторых диалектах BASIC на домашних компьютерах 1980-х годов , if–thenоператор мог содержать только GOTOоператоры (эквивалентные команде перехода ). Это привело к появлению трудночитаемого стиля программирования, известного как программирование спагетти , а программы в этом стиле называются кодом спагетти . В результате структурное программирование , которое позволяет (практически) помещать произвольные операторы в блоки операторов внутри оператора if, приобрело популярность, пока не стало нормой даже в большинстве кругов программирования на BASIC. Такие механизмы и принципы были основаны на более старом, но более совершенном семействе языков ALGOL , а языки, подобные ALGOL, такие как Pascal и Modula-2, в течение многих лет влияли на современные варианты BASIC. Хотя при использовании только GOTOоператоров в операторах можно if–thenписать программы, которые не являются спагетти-кодом и которые так же хорошо структурированы и читабельны, как и программы, написанные на структурированном языке программирования, структурное программирование упрощает эту задачу и обеспечивает ее соблюдение. Структурированные if–then–elseоператоры, подобные приведенному выше примеру, являются одним из ключевых элементов структурного программирования и присутствуют в большинстве популярных языков программирования высокого уровня, таких как C , Java , JavaScript и Visual Basic .

Проблема «висящего еще»

Ключевое elseслово предназначено для конкретного if–thenоператора, предшествующего ему, но для вложенных if–then операторов классические языки программирования, такие как ALGOL 60, изо всех сил пытались определить, какой конкретный оператор следует использовать. Без четких границ, для которых является оператором, elseключевое слово может быть нацелено на любой предыдущий if–thenоператор в вложении после анализа.

если а, то  если б , то s еще s2

можно проанализировать как

если а , то ( если б, то s) иначе s2

или

если а, то ( если б, то s , иначе s2)

в зависимости от того, elseсвязан ли он с первым ifили вторым if. Это известно как проблема висячего else и решается различными способами, в зависимости от языка (обычно с помощью end ifоператора или {...}скобок).

Иначе, если

Используя else if, можно объединить несколько условий. Будут выполняться только операторы, следующие за первым условием, которое окажется истинным. Все остальные операторы будут пропущены.

if условие then  -- операторы elseif условие then  -- дополнительные операторы elseif условие then  -- дополнительные операторы;...else  -- другие утверждения; конец, если ;

Например, для магазина, предлагающего скидку до 30% на товар:

если скидка < 11% , то распечатать (нужно заплатить 30$)иначе если скидка<21% , то распечатать (нужно заплатить 20 долларов)иначе, если скидка<31% , тогда распечатать (нужно заплатить 10 долларов)конец, если ;

В приведенном выше примере, если скидка составляет 10%, то первое утверждение if будет оценено как истинное и будет распечатано «вам придется заплатить 30 долларов». Все остальные операторы ниже первого оператора if будут пропущены.

Оператор , например, elseifна языке Ada , представляет собой просто синтаксический сахар , за которым elseследует if. В Ada разница в том, что end ifтребуется только один, если elseifвместо него elseследует if. PHP использует elseifключевое слово [1] как для фигурных скобок, так и для синтаксиса двоеточия. Perl предоставляет ключевое слово elsif, чтобы избежать большого количества фигурных скобок, которые потребовались бы для нескольких операторов ifand else. Python использует специальное ключевое слово elif, поскольку структура обозначается отступами, а не фигурными скобками, поэтому повторное использование elseи ifпотребует увеличения отступов после каждого условия. Некоторые реализации BASIC , такие как Visual Basic , [2] тоже используют ElseIf. Аналогично, более ранние оболочки UNIX (позже объединенные в синтаксис оболочки POSIX [3] ) также используют elif, но дают возможность выбора разделения пробелами, разрывами строк или тем и другим.

Однако во многих языках, более непосредственно произошедших от Algol, таких как Simula , Pascal , BCPL и C , этот специальный синтаксис для else ifконструкции отсутствует, а также он не присутствует во многих синтаксических производных от C, таких как Java , ECMAScript и скоро. Это работает, потому что в этих языках любой отдельный оператор (в данном случае ...) может следовать за условным выражением, не заключаясь в блок.if cond

Этот выбор дизайна имеет небольшую «стоимость». Каждая else ifветвь фактически добавляет дополнительный уровень вложенности. Это усложняет работу компилятора (или людей, которые его пишут), поскольку компилятор должен рекурсивно анализировать и реализовывать else ifцепочки произвольной длины.

Если все термины в последовательности условных выражений проверяют значение одного выражения (например, if x=0... else if x=1... else if x=2...), альтернативой является оператор переключения , также называемый оператором случая или оператором выбора. И наоборот, в языках, в которых нет оператора переключения, они могут быть созданы с помощью последовательности else ifоператоров.

Выражения if-then-else

Многие языки поддерживают выражения if , которые похожи на операторы if, но в результате возвращают значение. Таким образом, это истинные выражения (которые оцениваются как значения), а не операторы (которые могут быть недопустимы в контексте значения).

Семья Алголь

АЛГОЛ 60 и некоторые другие члены семейства АЛГОЛ допускают if–then–elseвыражение:

 моя переменная:= если x > 20, то 1, иначе 2

Диалекты Лиспа

В диалектах Лиспа Scheme , Racket и Common Lisp  — первый из которых в значительной степени был вдохновлен АЛГОЛом:

;; Схема ( определить мою переменную ( если ( > x 12 ) 1 2 )) ; Присваивает «myvariable» значение 1 или 2, в зависимости от значения «x».        
;; Common Lisp ( let (( x 10 )) ( setq myvariable ( if ( > x 12 ) 2 4 ))) ; Присваивает 'myvariable' значение 2           

Хаскелл

В Haskell 98 есть только выражение if , нет оператора if , и эта elseчасть является обязательной, поскольку каждое выражение должно иметь какое-то значение. [4] Логика, которая на других языках выражалась бы с помощью условий, обычно выражается с помощью сопоставления с образцом в рекурсивных функциях.

Поскольку Haskell ленив , можно писать управляющие структуры, например if , как обычные выражения; ленивая оценка означает, что функция if может оценивать только условие и правильную ветвь (тогда как строгий язык оценивает все три). Это можно записать так: [5]

if' :: Bool -> a -> a -> a if' True x _ = x if' False _ y = y                  

C-подобные языки

В языках C и C-подобных есть специальный тернарный оператор ( ?: ) для условных выражений с функцией, которая может быть описана таким шаблоном:

condition ? evaluated-when-true : evaluated-when-false

Это означает, что его можно встраивать в выражения, в отличие от операторов if, в C-подобных языках:

моя_переменная = х > 10 ? "фу" : "бар" ; // В C-подобных языках         

которые можно сравнить с выражениями if-then-else семейства Алголя (в отличие от оператора ) (и похожими, среди прочего, в Ruby и Scala).

Чтобы добиться того же с помощью оператора if, потребуется более одной строки кода (в соответствии с типичными соглашениями о макете) и дважды упомянуть «my_variable»:

если ( x > 10 ) my_variable = "foo" ; иначе my_variable = "бар" ;         

Некоторые утверждают, что явный оператор if/then легче читать и что он может скомпилироваться в более эффективный код, чем тернарный оператор, [6] в то время как другие утверждают, что краткие выражения легче читать, чем операторы, разбитые на несколько строк, содержащие повторения.

Маленький базовый

х = ТекстовоеОкно . ReadNumber () Если ( x > 10 ) Тогда TextWindow . WriteLine ( "Моя переменная называется 'foo'." ) Else TextWindow . WriteLine ( "Моя переменная называется 'bar'." ) EndIf        

Во-первых, когда пользователь запускает программу, появляется курсор, ожидающий, пока читатель наберет число. Если это число больше 10, появится текст «Моя переменная называется «foo». отображается на экране. Если число меньше 10, появится сообщение «Моя переменная называется «bar». печатается на экране.

Visual Basic

В Visual BasicIIf и некоторых других языках предусмотрена вызываемая функция , которую можно использовать как условное выражение. Однако оно не ведет себя как истинное условное выражение, поскольку всегда оцениваются как истинная, так и ложная ветви; просто результат одного из них выбрасывается, а результат другого возвращается функцией IIf.

Ткл

В Tcl if это не ключевое слово, а функция (в Tcl известная как команда или proc). Например

if { $x > 10 } { ставит "Фу!" }      

вызывает функцию с именем, ifпередающую 2 аргумента: первый — это условие, а второй — истинная ветвь. Оба аргумента передаются в виде строк (в Tcl все, что находится в фигурных скобках, является строкой).

В приведенном выше примере условие не оценивается перед вызовом функции. Вместо этого реализация функции ifполучает условие в виде строкового значения и отвечает за оценку этой строки как выражения в области вызывающего объекта. [7]

Такое поведение возможно с помощью команд uplevelи expr:

Uplevel позволяет реализовать новые конструкции управления как процедуры Tcl (например, uplevel можно использовать для реализации конструкции while как процедуры Tcl). [8]

Поскольку ifна самом деле это функция, она также возвращает значение:

Возвращаемое значение команды — это результат выполнения сценария тела или пустая строка, если ни одно из выражений не было отличным от нуля и не было телаN. [9]

Ржавчина

В Rust это ifвсегда выражение. Он оценивается по значению той ветви, которая выполняется, или по типу модуля, ()если ни одна ветвь не выполняется. Если ветвь не предоставляет возвращаемое значение, оно оценивается ()по умолчанию. Чтобы гарантировать, ifчто тип выражения известен во время компиляции, каждая ветвь должна оценивать значение одного и того же типа. По этой причине elseветвь фактически обязательна, если только другие ветви не оцениваются как (), потому что ifбез elseвсегда может оцениваться ()по умолчанию. [10]

// Присваиваем my_variable какое-то значение в зависимости от значения x let my_variable = if x > 20 { 1 } else { 2 };           // Этот вариант не скомпилируется, поскольку 1 и () имеют разные типы let my_variable = if x > 20 { 1 };        // Значения можно опускать, если они не нужны, если x > 20 { println! ( «x больше 20» ); }     

Арифметика, если

До Фортрана 77 язык Фортран имел оператор «арифметического if», который находится на полпути между вычисляемым IF и оператором case, основанным на трихотомии x < 0, x = 0, x > 0. Это был самый ранний условный оператор в Фортран: [11]

ЕСЛИ ( e ) метка1 , метка2 , метка3    

Где e — любое числовое выражение (не обязательно целое число); это эквивалентно

ЕСЛИ ( e . LT . 0 ) ПЕРЕЙТИ К метке 1 ЕСЛИ ( e . EQ . 0 ) ПЕРЕЙТИ К метке 2 ПЕРЕЙТИ К метке 3           

Поскольку этот арифметический IF эквивалентен нескольким GOTOоператорам, которые могут перейти куда угодно, он считается неструктурированным оператором управления и не должен использоваться, если можно использовать более структурированные операторы. На практике было замечено, что большинство арифметических IFоператоров ссылаются на следующий оператор с одной или двумя метками.

Это был единственный оператор условного управления в исходной реализации Фортрана на компьютере IBM 704 . На этом компьютере код операции тестирования и перехода имел три адреса для этих трех состояний. Другие компьютеры будут иметь регистры «флагов», такие как положительный, нулевой, отрицательный, четный, переполнение, перенос, связанные с последними арифметическими операциями, и будут использовать такие инструкции, как «Переход, если аккумулятор отрицательный», затем «Переход, если аккумулятор ноль» или аналогичные. Обратите внимание, что выражение вычисляется только один раз , и в таких случаях, как целочисленная арифметика, когда может произойти переполнение, также будут учитываться флаги переполнения или переноса.

Объектно-ориентированная реализация в Smalltalk

В отличие от других языков, в Smalltalk условный оператор не является языковой конструкцией , а определяется в классе Booleanкак абстрактный метод, который принимает два параметра, оба замыкания . Booleanимеет два подкласса Trueи False, оба из которых определяют метод, Trueвыполняя только первое замыкание и Falseвыполняя только второе замыкание. [12]

var  =  условие  ifTrue: [ 'foo' ] ifFalse: [ 'bar' ]

JavaScript

В JavaScript используются операторы if-else, аналогичные тем, которые используются в языках C. Логическое значение принимается в круглых скобках между зарезервированным ключевым словом if и левой фигурной скобкой.

если ( Math.random ( ) < 0,5 ) { console . _ log ( "У вас есть головы!" ); } Еще { консоль . log ( "У тебя Тейлс!" ); }        

В приведенном выше примере используется условие, Math.random() < 0.5которое выводит true, если случайное значение с плавающей запятой от 0 до 1 больше 0,5. Оператор использует его для случайного выбора между выводом You got Heads!или You got Tails!консолью. Операторы else и else-if также могут быть соединены после фигурной скобки предыдущего оператора столько раз, сколько необходимо, как показано ниже:

вар х = Математика . случайный (); если ( х < 1/3 ) { console . _ _ log ( "Выиграл один человек!" ); } Еще если ( х < 2/3 ) { console . _ _ log ( "Выиграли два человека!" ); } Еще { консоль . log ( "Это тройная ничья!" ); }                  

Лямбда-исчисление

В лямбда-исчислении концепция условия if-then-else может быть выражена с помощью следующих выражений:

истина = λx. λy. Иксложь = λx. λy. йifThenElse = (λc. λx. λy. (cxy))
  1. true принимает до двух аргументов, и как только оба они предоставлены (см. каррирование ), он возвращает первый заданный аргумент.
  2. false принимает до двух аргументов, и как только оба они предоставлены (см. каррирование ), он возвращает второй заданный аргумент.
  3. ifThenElse принимает до трех аргументов, и как только все они предоставлены, он передает второй и третий аргумент первому аргументу (который представляет собой функцию, которая передает два аргумента и выдает результат). Мы ожидаем, что ifThenElse будет принимать в качестве аргумента только true или false, оба из которых проецируют данные два аргумента на предпочитаемый ими единственный аргумент, который затем возвращается.

примечание : если ifThenElse переданы две функции: левая и правая условные выражения; необходимо также передать пустой кортеж () в результат ifThenElse, чтобы фактически вызвать выбранную функцию, в противном случае ifThenElse просто вернет объект функции без вызова .

В системе, где числа могут использоваться без определения (например, Lisp, традиционная бумажная математика и т. д.), вышеизложенное можно выразить как одно замыкание ниже:

 (( λtrue. λfalse. λifThenElse. ( ifThenElse true 2 3 ) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))                

Здесь true, false и ifThenElse привязаны к соответствующим определениям, которые передаются в их область действия в конце их блока.

Рабочая аналогия JavaScript (для строгости с использованием только функций с одной переменной) выглядит следующим образом:

 var ComputingResult = (( _true => _false => _ifThenElse => _ifThenElse ( _true )( 2 )( 3 ) )( x => y => x )( x => y => y )( c => x => y => c ( x )( y )));                          

Приведенный выше код с функциями с несколькими переменными выглядит следующим образом:

 var ComputingResult = (( _true , _false , _ifThenElse ) => _ifThenElse ( _true , 2 , 3 ) )(( x , y ) => x , ( x , y ) => y , ( c , x , y ) => с ( х , у ));                       

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

В первом примере показано использование первой ветви, а во втором примере показано использование второй ветви.

 (( λtrue. λfalse. λifThenElse. ( ifThenElse true ( λFirstBranch. FirstBranch ) ( λSecondBranch. SecondBranch )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))                   (( λtrue. λfalse. λifThenElse. ( ifThenElse false ( λFirstBranch. FirstBranch ) ( λSecondBranch. SecondBranch )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))                  

Smalltalk использует аналогичную идею для своих представлений true и false, при этом True и False являются одноэлементными объектами, которые по-разному реагируют на сообщения ifTrue/ifFalse.

Раньше Haskell использовал именно эту модель для своего логического типа, но на момент написания большинство программ Haskell использовали синтаксическую сахарную конструкцию «if a then b else c», которая, в отличие от ifThenElse, не компонуется, если она не обернута в другую функцию или не реализована повторно. как показано в разделе Haskell на этой странице.

Операторы Case и Switch

Операторы переключения (в некоторых языках операторы case или многосторонние ветки) сравнивают заданное значение с указанными константами и выполняют действия в соответствии с первой совпадающей константой. Обычно предусмотрено действие по умолчанию («иначе», «иначе»), которое должно быть выполнено, если совпадение не удалось. Операторы переключения могут обеспечивать оптимизацию компилятора , например таблицы поиска . В динамических языках регистры могут не ограничиваться постоянными выражениями и могут распространяться на сопоставление с образцом , как в примере сценария оболочки справа, где '*)' реализует регистр по умолчанию как регулярное выражение , соответствующее любой строке.

Сопоставление с образцом

Сопоставление с образцом можно рассматривать как альтернативу операторам if-then-else и case . Он доступен на многих языках программирования с функциями функционального программирования, таких как Wolfram Language , ML и многих других. Вот простой пример, написанный на языке OCaml :

сочетать  фрукты  с |  "яблоко"  ->  приготовить  пирог |  "кокос"  ->  приготовить  данго_моти |  "банан"  ->  микс ;;

Сила сопоставления шаблонов заключается в способности кратко сопоставлять не только действия, но и значения с шаблонами данных. Вот пример, написанный на Haskell , который иллюстрирует обе эти функции:

карта _ [] = [] карта ж ( час : т ) знак равно ж час : карта ж т               

Этот код определяет карту функции , которая применяет первый аргумент (функцию) к каждому из элементов второго аргумента (списка) и возвращает результирующий список. Две строки — это два определения функции для двух типов аргументов, возможных в этом случае: один, когда список пуст (просто возвращает пустой список), и другой случай, когда список не пуст.

Сопоставление с образцом, строго говоря, не всегда является конструкцией выбора, поскольку в Haskell можно написать только одну альтернативу, которая гарантированно всегда будет сопоставляться – в этой ситуации она используется не как конструкция выбора, а просто как способ для привязки имен к значениям. Однако он часто используется в качестве конструкции выбора на языках, на которых он доступен.

Условные выражения на основе хеша

В языках программирования, которые имеют ассоциативные массивы или сопоставимые структуры данных, таких как Python , Perl , PHP или Objective-C , идиоматично использовать их для реализации условного присваивания. [13]

pet  =  input ( «Введите тип домашнего животного, которого вы хотите назвать:» ) known_pets  =  {  «Собака» :  «Фидо» ,  «Кошка» :  «Мяуслз» ,  «Птица» :  «Твити» , } my_name  =  известные_питомцы [ домашнее животное ]

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

Предикация

Альтернативой инструкциям условного перехода является предикация . Предикация — это архитектурная особенность, которая позволяет выполнять инструкции в определенных условиях вместо изменения потока управления .

Перекрестная ссылка на систему выбора

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

  1. ^ Это относится к сопоставлению с образцом как к отдельной условной конструкции в языке программирования, в отличие от простой поддержки сопоставления строк с образцом, такой как поддержка регулярных выражений .
  2. 1 2 Директива #ELIF используется в подязыке препроцессора , который используется для изменения кода перед компиляцией; и включить другие файлы.
  3. 1 2 3 4 5 6 Часто встречающийся в семействе языков C, а также в COBOL и Haskell — это не особенность языка, а набор вложенных и независимых операторов if then else в сочетании с определенной компоновкой исходного кода. Однако это также означает, что отдельная конструкция else-if в этих языках на самом деле не нужна. else if
  4. 1 2 В Haskell и F# отдельная конструкция выбора констант не требуется, поскольку ту же задачу можно решить с помощью сопоставления с образцом.
  5. ^ В caseконструкции Ruby сопоставление регулярных выражений входит в число доступных альтернатив условного управления потоком. Пример см. в этом вопросе о переполнении стека.
  6. 1 2 В SQL есть две схожие конструкции, выполняющие обе роли, обе они представлены в SQL-92 . Выражение «поиск » работает как , тогда как «простое » выражение: работает как оператор переключения. Подробности и примеры см. в разделе Case (SQL) .CASECASE WHEN cond1 THEN expr1 WHEN cond2 THEN expr2 [...] ELSE exprDflt ENDif ... else if ... elseCASECASE expr WHEN val1 THEN expr1 [...] ELSE exprDflt END
  7. ^ Арифметика ifв Фортране 90 устарела.
  8. ^ Сопоставление с образцом было добавлено в Ruby 3.0. [16] Некоторые конструкции сопоставления с образцом все еще являются экспериментальными.

Смотрите также

Рекомендации

  1. ^ Синтаксис PHP elseif
  2. ^ Синтаксис Visual Basic ElseIf
  3. ^ Стандартный синтаксис оболочки POSIX
  4. ^ Язык Haskell 98 и библиотеки: пересмотренный отчет
  5. ^ «Предложение «если-то-иначе» на HaskellWiki»
  6. ^ «Эффективные советы по C № 6. Не используйте тернарный оператор «Переполнение стека». Embeddedgurus.com. 18 февраля 2009 г. Проверено 7 сентября 2012 г.
  7. ^ «Новые структуры управления». Вики Тклера . Проверено 21 августа 2020 г.
  8. ^ "Страница руководства более высокого уровня" . www.tcl.tk. _ Проверено 21 августа 2020 г.
  9. ^ "Если страница руководства" . www.tcl.tk. _ Проверено 21 августа 2020 г.
  10. ^ «Если и если выражения пусть» . Проверено 1 ноября 2020 г.
  11. ^ «Американский национальный стандартный язык программирования FORTRAN» . 3 апреля 1978 г. Архивировано из оригинала 11 октября 2007 г. Проверено 9 сентября 2007 г.
  12. ^ «VisualWorks: Условная обработка» . 16 декабря 2006 г. Архивировано из оригинала 22 октября 2007 г. Проверено 9 сентября 2007 г.
  13. ^ «Pythonic способ реализации операторов switch/case». Архивировано из оригинала 20 января 2015 г. Проверено 19 января 2015 г.
  14. ^ Java.sun.com, Спецификация языка Java, 3-е издание.
  15. ^ Ecma-international.org. Архивировано 12 апреля 2015 г. в спецификации языка ECMAScript Wayback Machine , 5-е издание.
  16. ^ «Сопоставление с образцом». Документация для Ruby 3.0 .

Внешние ссылки