Швидко, якщо нехай заява в Котліні


123

У Котліні є еквівалент коду Свіфта нижче?

if let a = b.val {

}
else {

}

Відповіді:


255

Ви можете використовувати let-функцію так:

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

Зауважте, що runфункцію потрібно викликати лише в тому випадку, якщо вам потрібен блок коду. Ви можете видалити run-block, якщо у вас буде лише oneliner після оператора elvis ( ?:).

Майте на увазі, що runблок буде оцінено або, якщо він bє нульовим, або якщо let-block оцінюється до null.

Через це ти, як правило, хочеш просто ifвиразу.

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

У цьому випадку else-блок буде оцінено лише у тому випадку, якщо bвін не є нульовим.


41
Це не рівнозначно. 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

Спершу переконаємось, що ми розуміємо семантику поданої ідіоми Свіфта:

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

Це означає це: "якщо <expr>результати не- thenнульові, необов'язково введіть -блок із символом, aприв'язаним до розпакованого значення. Інакше введіть elseблок.

Особливо зауважте, що aпов'язане лише в межах then-блока . У Котліні ви можете легко отримати це за телефоном

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

і ви можете додати else-блок так:

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

Це призводить до тієї ж семантики, що і ідіома Свіфта.


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, не потрібно розгортати необов'язковий. Ми можемо просто перевірити, чи значення не є нульовим, і компілятор відслідковує інформацію про здійснену вами перевірку та дозволяє використовувати її як розкручену.

У Свіфті:

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's Optional Binding(так званий if-letоператор) використовується для з'ясування того, чи містить необов'язкове значення, і якщо так, щоб зробити це значення доступним у якості тимчасової постійної чи змінної. Отже, формулювання Optional Bindingдля 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!  */

У Котліні, як і у 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Функція Котліна , коли використовується в поєднанні з оператором безпечного виклику ?:, забезпечує стислий спосіб обробляти нульові вирази.

Котлін еквівалент 2 (Inline let function та Elvis Operator) у 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вислів Свіфта :

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"
}

якщо name == null код у {} не виконувати, якщо name як String - код виконувати: nameUnwrapp == ім'я.
Олександр Яковенко

1
Я не думаю, що це запитує ОП, я впевнений, що ОП вже знає, що letробить, але питання стосується elseстратегії, яка виконується, якщо об'єкт, на який letвикликається, є null. Свіфт має це більш природним (суперечливим) способом. Але багато зробив Котліна та Свіфта, я б хотів, щоб у Котліна було просте розгортання, як це робив Свіфт.
kalehv

2

Ось мій варіант, обмежений дуже поширеним випадком "якщо не нульовим".

Перш за все, визначте це десь:

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)
}

Зауважте, що як завжди з блоками в Котліні, ви можете кинути аргумент і використовувати it:

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

Але якщо в блоці більше 1-2 рядків, мабуть, найкраще бути явним.

Це настільки ж схоже на Свіфт, як я міг знайти.


0

У котліні є подібний спосіб досягти стилю Свіфта, якщо нехай

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

Можна також призначити кілька нульових значень

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

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

джерело: Обговорення Котліна


1
Зауважте, що підхід, який ви показуєте, наразі не складається. Це лише пропозиція про те, як змінити мову Котліна для вирішення цього питання. Отже, це неправильне рішення.
Петро F

0

Я додаю цю відповідь, щоб уточнити прийняту відповідь, оскільки вона занадто велика для коментаря.

Загальна закономірність тут полягає в тому, що ви можете використовувати будь-яку комбінацію функцій діапазону, доступних у Котліні, розділених Оператором Елвіса, як це:

<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

Найчистіший варіант, на мою думку, такий

Швидкий:

if let a = b.val {

} else {

}

Котлін

b.val.also { a ->

} ?: run {

}

-1

Швидко, якщо нехай заява в Котліні

Коротка відповідь полягає у використанні простого IF-ELSE, оскільки на момент отримання цього коментаря в Kotlin LET немає еквівалента,

    if(A.isNull()){
// A is null
    }else{
// A is not null
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.