What does ?: làm gì ở Kotlin? (Nhà điều hành Elvis)


98

Tôi không thể tìm ra những gì ?:làm trong trường hợp này ví dụ

val list = mutableList ?: mutableListOf() 

và tại sao nó có thể được sửa đổi thành điều này

val list = if (mutableList != null) mutableList else mutableListOf()

5
Trả về bên trái nếu nó không phải là null, nếu không thì trả về bên phải. Biểu thức đầu tiên là ký hiệu ngắn gọn cho biểu thức thứ hai. kotlinlang.org/docs/reference/null-safety.html#elvis-operator
Eugen Pechanec

Câu trả lời:


115

TL; DR: Nếu không phải là tham chiếu đối tượng kết quả [toán hạng đầu tiên] null, nó sẽ được trả về. Nếu không, giá trị của toán hạng thứ hai (có thể là null) được trả về


Các nhà điều hành Elvis là một phần của nhiều ngôn ngữ lập trình, ví dụ như Kotlin mà còn Groovy hoặc C #. Tôi thấy định nghĩa Wikipedia khá chính xác:

Trong một số ngôn ngữ lập trình máy tính, toán tử Elvis ?:toán tử nhị phân trả về toán hạng đầu tiên nếu toán hạng đó là true, và nếu không thì sẽ đánh giá và trả về toán hạng thứ hai của nó. Đây là một biến thể của các nhà điều hành có điều kiện ternary , ? :được tìm thấy ở những ngôn ngữ (và nhiều người khác): các nhà điều hành Elvis là nhà điều hành ternary với toán hạng thứ hai của nó bỏ qua .

Điều sau đặc biệt đúng với Kotlin:

Một số ngôn ngữ lập trình máy tính có ngữ nghĩa khác nhau cho toán tử này. Thay vì toán hạng đầu tiên phải dẫn đến một boolean, nó phải dẫn đến một tham chiếu đối tượng . Nếu không phải là tham chiếu đối tượng kết quả null, nó sẽ được trả về. Nếu không, giá trị của toán hạng thứ hai (có thể là null) được trả về.

Một ví dụ:

x ?: y // yields `x` if `x` is not null, `y` otherwise.

3
Điều này thực sự tuyệt vời. Tôi không bao giờ nghĩ rằng elvis operatorcó thể được giảm thêm thành một cái gì đó khác. đẹp! Và lời giải thích tốt đẹp, cảm ơn bạn!
sud007

87

Các Elvis điều hành được đại diện bởi một dấu chấm hỏi sau bằng dấu hai chấm: ?:và nó có thể được sử dụng với cú pháp sau:

first operand ?: second operand

Nó cho phép bạn viết mã khuyết điểm và hoạt động như sau:

Nếu first operand không phải null , thì nó sẽ được trả về. Nếu nó là null , thì second operandsẽ được trả về. Điều này có thể được sử dụng để đảm bảo rằng một biểu thức sẽ không trả về giá trị null, vì bạn sẽ cung cấp một giá trị không thể null nếu giá trị được cung cấp là null.


Ví dụ (trong Kotlin):

fun retrieveString(): String {    //Notice that this type isn't nullable
    val nullableVariable: String? = getPotentialNull() //This variable may be null
    
    return nullableVariable ?: "Secondary Not-Null String"
}

Trong trường hợp này, nếu giá trị đã tính của getPotentialNullkhông phải là null, nó sẽ được trả về bởi retrieveString; Nếu nó là null, biểu thức thứ hai "Secondary Not-Null String"sẽ được trả về thay thế.

Cũng lưu ý rằng biểu thức phía bên phải chỉ được đánh giá nếu phía bên trái là rỗng .

Trong Kotlin, bạn có thể sử dụng bất kỳ biểu thức nào second operand, chẳng hạn như throw Exceptionbiểu thức

return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")

Cái tên Elvis Operator bắt nguồn từ ca sĩ nổi tiếng người Mỹ Elvis Presley . Kiểu tóc của anh ấy giống Dấu chấm hỏi

Elvis QuestionMark

Nguồn: Wojda, I. Moskala, M. Phát triển Android với Kotlin. 2017. Packt Publishing


83
Plus 1 cho minh họa Ông Presley
s1m0nw1

7
? :) (xem nó như Elvis mỉm cười)
LeoColman

1
Sau một thời gian, tôi không thể hiểu tại sao nó được gọi là Elvis Operator. Hình minh họa của bạn khiến tôi biết tại sao nó được gọi là Toán tử Elvis. :)
Yohanes AI

câu chuyện về Elvis có thật không? haha
Hillcow

@Kerooker Anh ấy không cười,?: | IMO sẽ tốt hơn.
ahmed galal

38

Đây được gọi là toán tử Elvis và nó thực hiện ... Chính xác những gì bạn đã mô tả trong câu hỏi của mình. Nếu phía bên trái của nó là một nullgiá trị, nó sẽ trả về phía bên phải thay vào đó, giống như một dự phòng. Nếu không, nó chỉ trả về giá trị ở phía bên trái.

a ?: bchỉ là viết tắt của if (a != null) a else b.

Một số ví dụ khác với các loại:

val x: String? = "foo"
val y: String = x ?: "bar"      // "foo", because x was non-null    

val a: String? = null
val b: String = a ?: "bar"      // "bar", because a was null

10
nếu bạn đến từ java, nó nhiều hơn một cách viết tắt cho:a != null ? a : b
crgarridos

9

Chúng ta hãy nhìn vào độ lệch :

Khi chúng ta có một tham chiếu nullable r, chúng ta có thể nói "nếu r không null, hãy sử dụng nó, nếu không hãy sử dụng một số giá trị không null x":

Các ?:(Elvis) điều hành tránh rườm rà và làm cho mã của bạn thực sự súc tích.

Ví dụ: rất nhiều hàm mở rộng bộ sưu tập trả về nulldưới dạng dự phòng.

listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")

?:cung cấp cho bạn cách xử lý trường hợp dự phòng một cách nhanh chóng ngay cả khi bạn có nhiều lớp dự phòng. Nếu vậy, bạn có thể đơn giản chuỗi nhân các toán tử Elvis, như sau:

val l = listOf(1, 2, 3)

val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")

Nếu bạn cũng diễn đạt tương tự với nếu khác thì sẽ có nhiều mã khó đọc hơn.


3

Đơn giản chúng tôi có thể nói rằng, bạn có hai tay. Bạn muốn biết, bây giờ tay trái của bạn có đang hoạt động không? Nếu tay trái không hoạt động, return emptykhácbusy

Ví dụ cho Java:

private int a;
if(a != null){
    println("a is not null, Value is: "+a)
}
else{
    println("a is null")
}

Ví dụ cho Kotlin:

val a : Int = 5
val l : Int = if (a != null) a.length else "a is null"

Thích câu trả lời này. Quá sạch để hiểu.
Gk Mohammad Emon

2

Về cơ bản, nếu phần bên trái của Elvis trả về null vì lý do nào đó, hãy trả về phần bên phải thay thế.

I E

val number: Int? = null
println(number ?: "Number is null")

Vì vậy, nếu số KHÔNG rỗng , nó sẽ in số, ngược lại sẽ in "Số là null".


1

Toán tử elvis trong Kotlin được sử dụng cho an toàn rỗng.

x = a ?: b

Trong đoạn mã trên, xsẽ được gán giá trị anếu a không nullbnếu anull.

Dưới đây là mã kotlin tương đương mà không sử dụng toán tử elvis:

x = if(a == null) b else a

1

Tuy nhiên, một bổ sung nhỏ là đây

X = A ?: B

Xvẫn sẽ là nullnếu cả hai ABđánh giánull

Do đó, nếu bạn muốn Xluôn là như vậy non-null, hãy đảm bảo Bluôn là một non-nullhoặc Bluôn luôn đánh giá non-nullxem đó là một hàm hay biểu thức.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.