Оператор Swift if let в Котлине

123

Есть ли в Котлине эквивалент приведенного ниже кода Swift?

if let a = b.val {

}
else {

}
iori24
источник

Ответы:

255

Вы можете использовать эту letфункцию следующим образом:

val a = b?.let {
    // If b is not null.
} ?: run {
    // If b is null.
}

Обратите внимание, что вам нужно вызывать runфункцию, только если вам нужен блок кода. Вы можете удалить run-block, если у вас есть только одна строка после elvis-operator ( ?:).

Имейте в виду, что runблок будет оценен либо если bравен нулю, либо если let-block оценивается как null.

Из-за этого обычно требуется просто ifвыражение.

val a = if (b == null) {
    // ...
} else {
    // ...
}

В этом случае else-block будет оцениваться, только если bне равен нулю.

marstran
источник
42
Это не эквивалент. aнельзя получить доступ внутрь letи runзаблокировать.
Джеки Чой
6
aеще не определен в рамках letи run. Но вы можете получить доступ к значению bвнутри letс помощью неявного параметра it. Думаю, это служит той же цели.
marstran
1
Быстрый код завершает назначение aперед этими блоками кода. И aможно попасть внутрь.
Джеки Чой
1
К чему это относится a? Если да b, то itслужит той же цели. Переназначается ли aс результатом val-блока?
marstran
3
Вы можете получить доступ только itиз letблока. Результат блока letили runбудет присвоен a. Результатом будет последнее выражение в блоке. Вы можете использовать назначение после let того, как / runзакончил, так же , как вы делаете с любым другим нормальным назначением.
marstran
51

Давайте сначала убедимся, что мы понимаем семантику предоставленной идиомы Swift:

if let a = <expr> {
     // then-block
}
else {
     // else-block
}

Это означает следующее: «если <expr>результатом является необязательный параметр, thenотличный от nil, введите -блок с символом, aпривязанным к развернутому значению. В противном случае введите elseблок.

Особо обратите внимание, что aэто связано только с then-block . В Котлине вы можете легко получить это, позвонив

<expr>?.also { a ->
    // then-block
}

и вы можете добавить else-блок следующим образом:

<expr>?.also { a ->
    // then-block
} ?: run {
    // else-block
}

Это приводит к той же семантике, что и идиома Swift.

Марко Топольник
источник
11

Мой ответ полностью копирует других. Однако я не могу легко понять их выражение. Думаю, было бы неплохо дать более понятный ответ.

Быстро:

if let a = b.val {
  //use "a" as unwrapped
}
else {

}

В Котлине:

b.val?.let{a -> 
  //use "a" as unwrapped
} ?: run{
  //else case
}
У Юань Чун
источник
Использование letвместо alsoозначает, что runблок будет выполняться всякий раз, когда letблок возвращается null, а это не то, что мы хотим.
Марко Топольник
6

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

В Swift:

if let a = b.val {
  //use "a" as unwrapped
} else {

}

В Котлине:

if b.val != null {
  //use "b.val" as unwrapped
} else {

}

Обратитесь к документации: (нулевая безопасность) для получения дополнительных примеров использования

Шахзин К.С.
источник
Это работает, только если b - локальная переменная. А как насчет переменных класса?
Warpzit
5

if let заявление.

Swift Optional Binding(так называемый if-letоператор) используется, чтобы узнать, содержит ли необязательный параметр значение, и если да, то сделать это значение доступным как временную константу или переменную. Итак, оператор Optional Bindingfor if-letвыглядит следующим образом:

if-letЗаявление Свифта :

let b: Int? = 50

if let a = b {
    print("Good news!")
} else {
    print("Equal to 'nil' or not set")
}

/*  RESULT: Good news!  */

В Kotlin, как и в Swift, чтобы избежать сбоев, вызванных попыткой доступа к нулевому значению, когда это не ожидается, b.let { }для правильного развертывания предоставляется специальный синтаксис (например, во втором примере) nullable types:

Котлинский эквивалент 1if-let утверждения Свифта :

val b: Int? = null
val a = b

if (a != null) { 
    println("Good news!")
} else { 
    println("Equal to 'null' or not set")
}

/*  RESULT: Equal to 'null' or not set  */

letФункция Kotlin при использовании в сочетании с оператором безопасного вызова ?:предоставляет краткий способ обработки выражений, допускающих значение NULL.

Котлинский эквивалент 2 (функция Inline let и оператор Элвиса) оператора Swift if-let:

val b: Int? = null

val a = b.let { nonNullable -> nonNullable } ?: "Equal to 'null' or not set"
println(a)

/*  RESULT: Equal to 'null' or not set  */

введите описание изображения здесь

guard let заявление.

guard-letОператор Swift прост и эффективен. Он проверяет наличие некоторого условия, и если оно оказывается ложным, elseвыполняется инструкция, которая обычно завершает метод.

Давайте рассмотрим guard-letутверждение Swift :

let b: Int? = nil

func testIt() {
    guard let a = b else {
        print("Equal to 'nil' or not set")
        return
    }
    print("Good news!")
}
testIt()

/*  RESULT: Equal to 'nil' or not set  */

Котлин, аналогичный эффектуguard-let заявления Свифта :

В отличие от Свифта, в Котлине нет никакого охранного заявления. Однако вы можете использовать Elvis Operator- ?:для получения аналогичного эффекта.

val b: Int? = 50

fun testIt() {
    val a = b ?: return println("Equal to 'null' or not set")
    return println("Good news!")
}
testIt()

/*  RESULT: Good news!  */

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

Энди Федоров
источник
4

Вот как выполнить код, только если nameон не равен нулю:

var name: String? = null
name?.let { nameUnwrapp ->
    println(nameUnwrapp)  // not printed because name was null
}
name = "Alex"
name?.let { nameUnwrapp ->
    println(nameUnwrapp)  // printed "Alex"
}
Александр Яковенко
источник
если имя == нулевой код в {} не выполняется, если имя как String - выполняется код: nameUnwrapp == name.
Александр Яковенко
1
Я не думаю, что это то, о чем спрашивает OP, я уверен, что OP уже знает, что letделает, но вопрос заключается в elseстратегии, которая выполняется, если объект, для которого letвызывается, является null. Swift имеет его более естественным (спорного) способом. Но, сделав много работы как с Kotlin, так и с Swift, я действительно хочу, чтобы у Kotlin была простая распаковка, как у Swift.
kalehv
2

Вот мой вариант, ограниченный очень распространенным случаем «if not null».

Прежде всего, определите это где-нибудь:

inline fun <T> ifNotNull(obj: T?, block: (T) -> Unit) {
    if (obj != null) {
        block(obj)
    }
}

Наверное, так и должно быть internal, чтобы не было конфликтов.

Теперь преобразуйте этот код Swift:

if let item = obj.item {
    doSomething(item)
}

К этому коду Котлина:

ifNotNull(obj.item) { item -> 
    doSomething(item)
}

Обратите внимание, что, как всегда с блоками в Kotlin, вы можете отбросить аргумент и использовать it:

ifNotNull(obj.item) {
    doSomething(it)
}

Но если в блоке больше 1-2 строк, вероятно, лучше указать явно.

Это похоже на Swift, насколько я смог найти.

noamtm
источник
0

В kotlin есть аналогичный способ достичь стиля Swift if-let

if (val a = b) {
    a.doFirst()
    a.doSecond()
}

Вы также можете назначить несколько значений, допускающих значение NULL

if (val name = nullableName, val age = nullableAge) {
    doSomething(name, age)
}

Такой подход будет более подходящим, если значения, допускающие значение NULL, используются более 1 раза. На мой взгляд, это помогает с точки зрения производительности, потому что значение, допускающее значение NULL, будет проверяться только один раз.

источник: Kotlin Discussion

Ричард
источник
1
Имейте в виду, что показываемый вами подход в настоящее время не компилируется. Это только предложение о том, как изменить язык Kotlin для решения этой проблемы. Следовательно, это неправильное решение.
Peter F
0

Я добавляю этот ответ, чтобы прояснить принятый ответ, потому что он слишком велик для комментария.

Общий шаблон здесь заключается в том, что вы можете использовать любую комбинацию функций Scope, доступных в Kotlin, разделенных оператором Elvis, например:

<nullable>?.<scope function> {
    // code if not null
} :? <scope function> {
    // code if null
}

Например:

val gradedStudent = student?.apply {
    grade = newGrade
} :? with(newGrade) {
    Student().apply { grade = newGrade }
}
Сэр Кодесалот
источник
-1

Самый чистый вариант на мой взгляд - это

Swift:

if let a = b.val {

} else {

}

Котлин

b.val.also { a ->

} ?: run {

}
Stiiv
источник
-1

Оператор Swift if let в Котлине

Короткий ответ: используйте простой IF-ELSE, поскольку на момент написания этого комментария эквивалента в Kotlin LET нет,

    if(A.isNull()){
// A is null
    }else{
// A is not null
    }
bastami82
источник