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

Руководство по блоку «когда \ <>» в Котлине

В этом руководстве представлен блокwhen\<> на языке Kotlin и показаны различные способы его использования.

Чтобы понять материал этой статьи, необходимы базовые знания языка котлин. Вы можете взглянуть на статьюintroduction to the Kotlin Language на примере, чтобы узнать больше о языке.

2. Блокwhen\<> Котлина

БлокWhen\<> по сути является расширенной формой оператораswitch-case, известного из Java.

В Kotlin, если соответствующий регистр найден, то выполняется только код в соответствующем блоке case, и выполнение продолжается со следующего оператора после блокаwhen. По сути, это означает, что в конце каждого блокаcase не требуется никаких операторов break.

Чтобы продемонстрировать использованиеwhen\<>, давайте определим класс перечисления, который содержит первую букву в поле разрешений для некоторых типов файлов в Unix:

Давайте также определим иерархию классов, которые моделируют соответствующие типы файлов Unix:

sealed class UnixFile < abstract fun getFileType(): UnixFileType class RegularFile(val content: String) : UnixFile() < override fun getFileType(): UnixFileType < return UnixFileType.HYPHEN_MINUS >> class Directory(val children: List) : UnixFile() < override fun getFileType(): UnixFileType < return UnixFileType.D >> class SymbolicLink(val originalFile: UnixFile) : UnixFile() < override fun getFileType(): UnixFileType < return UnixFileType.L >> >

2.1. When\<> как выражение

Большое отличие от оператора switch в Java состоит в том, чтоthe when\<> block in Kotlin can be used both as a statement and as an expression. Kotlin следует принципам других функциональных языков, а структуры управления потоком представляют собой выражения, и результат их оценки может быть возвращен вызывающей стороне.

Читайте также:  Python таймер выполнения кода

Если возвращаемое значение присваивается переменной, компилятор проверит, что тип возвращаемого значения совместим с типом, ожидаемым клиентом, и сообщит нам, если это не так:

@Test fun testWhenExpression() < val directoryType = UnixFileType.D val objectType = when (directoryType) < UnixFileType.D ->"d" UnixFileType.HYPHEN_MINUS -> "-" UnixFileType.L -> "l" > assertEquals("d", objectType) >

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

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

Второе, на что следует обратить внимание, — это то, что мы должны гарантировать, что вызывающий объект получит значение. Чтобы это произошло, мы должны убедиться, что случаи в блоке when охватывают все возможные значения, которые могут быть назначены аргументу.

2.2. When\<> как выражение с регистром по умолчанию

Случай по умолчанию будет соответствовать любому значению аргумента, которое не соответствует нормальному регистру, и в Kotlin объявляется с использованием предложенияelse. В любом случае, компилятор Kotlin будет предполагать, что каждое возможное значение аргумента покрывается блоком when, и будет жаловаться, если это не так.

Чтобы добавить регистр по умолчанию в выражение Kotlinwhen:

@Test fun testWhenExpressionWithDefaultCase() < val fileType = UnixFileType.L val result = when (fileType) < UnixFileType.L ->"linking to another file" else -> "not a link" > assertEquals("linking to another file", result) >

2.3. When\<> Expression with a Case That Throws an Exception

В Kotlinthrow возвращает значение типаNothing.

В этом случаеNothing используется, чтобы объявить, что выражению не удалось вычислить значение. Nothing — это тип, который наследуется от всех пользовательских и встроенных типов в Kotlin.

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

Давайте определим выражение when, в котором один из случаев вызывает исключение:

@Test(expected = IllegalArgumentException::class) fun testWhenExpressionWithThrowException() < val fileType = UnixFileType.L val result: Boolean = when (fileType) < UnixFileType.HYPHEN_MINUS ->true else -> throw IllegalArgumentException("Wrong type of file") > >

2.4. When\<> используется как утверждение

Мы также можем использовать блокwhen в качестве оператора.

В этом случае нам не нужно указывать все возможные значения для аргумента, а значение, вычисленное в каждом блоке, если оно есть, просто игнорируется. При использовании в качестве оператора блокwhen можно использовать аналогично тому, как операторswitch используется в Java.

Давайте использовать блокwhen как инструкцию:

@Test fun testWhenStatement() < val fileType = UnixFileType.HYPHEN_MINUS when (fileType) < UnixFileType.HYPHEN_MINUS ->println("Regular file type") UnixFileType.D -> println("Directory file type") > >

Из этого примера видно, что необязательно охватывать все возможные значения аргументов, когда мы используемwhen в качестве оператора.

2.5. Объединение случаевWhen\<>

Выражениеwhen в Kotlin позволяет нам объединить разные случаи в один, объединив условия сопоставления с запятой.

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

Давайте создадим кейс, в котором сочетаются два условия:

@Test fun testCaseCombination() < val fileType = UnixFileType.D val frequentFileType: Boolean = when (fileType) < UnixFileType.HYPHEN_MINUS, UnixFileType.D ->true else -> false > assertTrue(frequentFileType) >

2.6. When\<> используется без аргумента

Kotlin позволяет нам опускать значение аргумента в блокеwhen.

По сути, это происходит в простом выраженииif-elseif, которое последовательно проверяет случаи и выполняет блок кода первого совпадающего варианта. Если мы опускаем аргумент в блоке when, тогда выражения case должны иметь значение true или false.

Давайте создадим блокwhen без аргумента:

@Test fun testWhenWithoutArgument() < val fileType = UnixFileType.L val objectType = when < fileType === UnixFileType.L ->"l" fileType === UnixFileType.HYPHEN_MINUS -> "-" fileType === UnixFileType.D -> "d" else -> "unknown file type" > assertEquals("l", objectType) >

2.7. Динамические выражения регистра

В Java операторswitch может использоваться только с примитивами и их упакованными типами, перечислениями и классомString. Напротив,Kotlin allows us to use the when block with any built-in or user defined type.

Кроме того, не требуется, чтобы случаи были константными выражениями, как в Java. Случаи в Kotlin могут быть динамическими выражениями, которые оцениваются во время выполнения. Например, случаи могут быть результатом функции, если тип возвращаемого значения функции совместим с типом аргумента блокаwhen.

Давайте определим блокwhen с динамическими выражениями case:

@Test fun testDynamicCaseExpression() < val unixFile = UnixFile.SymbolicLink(UnixFile.RegularFile("Content")) when < unixFile.getFileType() == UnixFileType.D ->println("It's a directory!") unixFile.getFileType() == UnixFileType.HYPHEN_MINUS -> println("It's a regular file!") unixFile.getFileType() == UnixFileType.L -> println("It's a soft link!") > >

2.8. Выражения Range и Collection Case

Можно определить регистр в блокеwhen, который проверяет, содержит ли данная коллекция или диапазон значений аргумент.

По этой причине Kotlin предоставляет операторin, который является синтаксическим сахаром для методаcontains(). Это означает, что Kotlin за кулисами переводит элемент casein в collection.contains (element).

Чтобы проверить, есть ли аргумент в списке:

@Test fun testCollectionCaseExpressions() < val regularFile = UnixFile.RegularFile("Test Content") val symbolicLink = UnixFile.SymbolicLink(regularFile) val directory = UnixFile.Directory(listOf(regularFile, symbolicLink)) val isRegularFileInDirectory = when (regularFile) < in directory.children ->true else -> false > val isSymbolicLinkInDirectory = when < symbolicLink in directory.children ->true else -> false > assertTrue(isRegularFileInDirectory) assertTrue(isSymbolicLinkInDirectory) >

Чтобы проверить, что аргумент находится в диапазоне:

@Test fun testRangeCaseExpressions() < val fileType = UnixFileType.HYPHEN_MINUS val isCorrectType = when (fileType) < in UnixFileType.D..UnixFileType.L ->true else -> false > assertTrue(isCorrectType) >

Несмотря на то, что типREGULAR_FILE явно не содержится в диапазоне, его порядковый номер находится между порядковыми номерамиDIRECTORY иSYMBOLIC_LINK, и поэтому проверка прошла успешно.

2.9. Is Case Operator и Smart Cast

Мы можем использовать операторis в Kotlin, чтобы проверить, является ли аргумент экземпляром указанного типа. Операторis похож на операторinstanceof в Java.

Тем не менее, Kotlin предоставляет нам функцию под названием «Smart Cast». После того, как мы проверим, является ли аргумент экземпляром данного типа, нам не нужно явно приводить аргумент к этому типу, поскольку компилятор делает это за нас.

Следовательно, мы можем использовать методы и свойства, определенные в данном типе, непосредственно в блоке case. Чтобы использовать оператор is с функцией «умного приведения» в блокеwhen:

@Test fun testWhenWithIsOperatorWithSmartCase() < val unixFile: UnixFile = UnixFile.RegularFile("Test Content") val result = when (unixFile) < is UnixFile.RegularFile ->unixFile.content is UnixFile.Directory -> unixFile.children.map < it.getFileType() >.joinToString(", ") is UnixFile.SymbolicLink -> unixFile.originalFile.getFileType() > assertEquals("Test Content", result) >

Без явного преобразованияunixFile вRegularFile,Directory илиSymbolicLink мы смогли использоватьRegularFile.content,Directory.children иSymbolicLink.originalFile соответственно.

3. Заключение

В этой статье мы видели несколько примеров того, как использовать блокwhen, предлагаемый языком Kotlin.

Несмотря на то, что сопоставление с образцом с использованиемwhen в Kotlin невозможно, как в случае с соответствующими структурами в Scala и других языках JVM, блокwhen достаточно универсален, чтобы мы полностью забыли об этом. Особенности.

Полную реализацию примеров для этой статьи можно найти вover on GitHub.

Источник

Как работает инструкция when с сопоставлением с образцом в Kotlin?

Инструкция when с сопоставлением с образцом в Kotlin позволяет написать компактный и читаемый код, который может заменить насыщенную ветвление if-else конструкцию.

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

Вот несколько примеров использования инструкции when с сопоставлением с образцом в Kotlin:

val x = 1 when (x) < 1 ->print("x is 1") 2 -> print("x is 2") else -> print("x is neither 1 nor 2") >

В этом примере мы проверяем значение переменной `x` на соответствие значениям 1 и 2, и выводим сообщение, соответствующее тому, какое из них соответствует.

val x = "hello" when (x) < is String ->print("x is a String") !is String -> print("x is not a String") >

В этом примере мы проверяем, является ли значением переменной `x` строка и выводим соответствующее сообщение.

val x = 50 when < x < 40 ->print("x is less than 40") x in 40..60 -> print("x is between 40 and 60") x > 60 -> print("x is greater than 60") >

В этом примере мы проверяем значение, используя только логические условия.

В общем случае, в операторе when можно указывать несколько условий. Например:

val x = 3 val message = when (x) < 1, 2 ->"x is one or two" 3, 4 -> "x is three or four" else -> "x is not one, two, three, or four" > println(message)
val x = Pair(10, "foo") when (x) < is Pair-> print("x is a Pair with Int and String") is Pair -> print("x is a Pair with Int and Double") else -> print("x is not a Pair") >

Как видно из примеров, использование инструкции when вместе с сопоставлением с образцом позволяет упростить и укоротить код во многих случаях.

Похожие записи:

Источник

Оцените статью