Nhà điều hành có điều kiện của Kotlin Ternary


Câu trả lời:


617

Trong Kotlin, các ifcâu lệnh là biểu thức. Vì vậy, đoạn mã sau là tương đương:

if (a) b else c

Sự phân biệt giữa biểu thức và tuyên bố là quan trọng ở đây. Trong Java / C # / JavaScript, iftạo thành một câu lệnh, nghĩa là nó không phân giải thành một giá trị. Cụ thể hơn, bạn không thể gán nó cho một biến.

// Valid Kotlin, but invalid Java/C#/JavaScript
var v = if (a) b else c

Nếu bạn đến từ một ngôn ngữ iflà một tuyên bố, điều này có vẻ không tự nhiên nhưng cảm giác đó sẽ sớm lắng xuống.


57
Ngoài ra, bạn có thể sử dụng when.
bashor

5
chỉ cần thêm, nếu đó là một biểu thức boolean, bạn thậm chí có thể đi vớix = a==b
gnomeria

2
@MikeRylander Tôi đã mở rộng câu trả lời để làm rõ điều này. Cảm ơn đã chỉ ra điều này.
Drew Noakes

1
@AdeelAnsari Không, nó không được chỉnh sửa. Nó là tồi tệ hơn. So sánh điều này. b + if (a) c else dso với b + (c if (a) else d)cái sau đòi hỏi dấu ngoặc đơn bổ sung. bởi vì ckhông được bao bọc bởi các điều kiện và else.
Naetmul

1
Đây là một cuộc thảo luận nhỏ về chủ đề này. thảo luận.kotlinlang.org/t/ternary
F. Norbert

70

Bạn có thể định nghĩa của riêng bạn Booleanchức năng mở rộng mà lợi nhuận nullkhi Booleanfalseđể cung cấp một cấu trúc tương tự như các nhà điều hành ternary:

infix fun <T> Boolean.then(param: T): T? = if (this) param else null

Điều này sẽ làm cho một a ? b : cbiểu thức dịch thành a then b ?: c, như vậy:

println(condition then "yes" ?: "no")

Cập nhật: Nhưng để thực hiện một số chuyển đổi có điều kiện giống Java hơn, bạn sẽ cần một cái gì đó tương tự

infix fun <T> Boolean.then(param: () -> T): T? = if (this) param() else null

println(condition then { "yes" } ?: "no") chú ý đến lambda. tính toán nội dung của nó nên được hoãn lại cho đến khi chúng tôi đảm bảoconditiontrue

Điều này có vẻ vụng về, đó là lý do tại sao có yêu cầu đòi hỏi cao tồn tại để chuyển toán tử ternary Java vào Kotlin


1
infix inline fun<T> Boolean.then(param: ()->T):T? = if(this) param() else null
nullbyte

3
Sử dụng <T: Any>, nếu không, nó sẽ hoạt động không chính xác:true then { null } ?: "not-null"
Eugene Petrenko

BTW, ?:nhà điều hành ở đây là elvis-operator: kotlinlang.org/docs/reference/null-safe.html#elvis-operator
Eric Wang

64

TL; DR

if (a) b else c

là những gì bạn có thể sử dụng thay vì biểu thức toán tử ternary a ? b : c.


Trong Kotlin, nhiều câu lệnh điều khiển bao gồm if, whenhoặc thậm chí trycó thể được sử dụng làm biểu thức . Điều này có nghĩa là những cái đó có thể có một kết quả có thể được gán cho một biến, được trả về từ một hàm, v.v.

Về mặt cú pháp, không cần người vận hành ternary

Do kết quả của các biểu thức của Kotlin, ngôn ngữ không thực sự cần toán tử ternary .

if (a) b else c

là những gì bạn có thể sử dụng thay vì biểu thức toán tử ternary a ? b : c.

Tôi nghĩ ý tưởng là biểu thức trước dễ đọc hơn vì mọi người đều biết ifelsenó làm gì , trong khi đó ? :vẫn chưa rõ ràng nếu bạn chưa quen với cú pháp.

Tuy nhiên, tôi phải thừa nhận rằng tôi thường bỏ lỡ các nhà điều hành ternary thuận tiện hơn.


Các lựa chọn thay thế khác

khi nào

Bạn cũng có thể thấy các whencấu trúc được sử dụng trong Kotlin khi các điều kiện được kiểm tra. Đó cũng là một cách để thể hiện thác nếu khác theo cách khác. Sau đây tương ứng với ví dụ OTs.

when(a) {
    true -> b
    false -> c
}

Tiện ích mở rộng

Như nhiều ví dụ hay ( Nhà điều hành có điều kiện của Kotlin Ternary ) trong các câu trả lời khác cho thấy, các tiện ích mở rộng cũng có thể giúp giải quyết trường hợp sử dụng của bạn.


36

Đối với bản thân tôi, tôi sử dụng các chức năng mở rộng sau:

fun T?.or<T>(default: T): T = if (this == null) default else this 
fun T?.or<T>(compute: () -> T): T = if (this == null) compute() else this

Đầu tiên sẽ trả về giá trị mặc định được cung cấp trong trường hợp đối tượng bằng null. Thứ hai sẽ đánh giá biểu thức được cung cấp trong lambda trong trường hợp tương tự.

Sử dụng:

1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }

Cá nhân đối với tôi mã ở trên dễ đọc hơn ifxây dựng nội tuyến


34
Nó không liên quan đến câu hỏi, nhưng tại sao không sử dụng ?: , Toán tử elvis ? Các chức năng đầu tiên sẽ được thay thế bằng e.getMessage() ?: "unknown". Thứ hai có thể được thể hiện làobj?.lastMessage?.timestamp ?: { Date() }()
hotkey

1
@hotkey không có mục đích đặc biệt cho việc đó. Theo quan điểm của tôi, nó trông có vẻ nhất quán hơn và ít ồn ào hơn trong các hoạt động của chuỗi vì bạn không nên bọc công trình trong ngoặc
ruX

14
@ruX toán tử elvis dành riêng cho việc này và việc sử dụng của bạn khá bất thường.
Jayson Minard

6
Trong khi?: Vẫn ổn, chúng ta đừng đi quá xa đến Perl.
Richard Haven

29

Java tương đương với toán tử ternary

a ? b : c

là một IF đơn giản trong Kotlin trong một dòng

if(a) b else c

không có toán tử ternary (điều kiện? sau đó: khác), bởi vì bình thường nếu hoạt động tốt trong vai trò này.

https://kotlinlang.org/docs/reference/control-flow.html#if-expression


Trường hợp đặc biệt để so sánh Null

bạn có thể sử dụng toán tử Elvis

if ( a != null ) a else b
// equivalent to
a ?: b

28

Không có toán tử ternary trong kotlin, vì if elsekhối trả về giá trị

vì vậy, bạn có thể làm: val max = if (a > b) a else b thay vì javamax = (a > b) ? b : c

Chúng tôi cũng có thể sử dụng whenxây dựng, nó cũng trả về giá trị:

val max = when(a > b) {
    true -> a
    false -> b
}

Đây là liên kết cho tài liệu kotlin: Control Flow: if, when, for, while


27

Trong Kotlin, iflà một biểu thức, tức là nó trả về một giá trị. Do đó, không có toán tử ternary (condition ? then : else), vì bình thường nếu hoạt động tốt trong vai trò này. nguồn thủ công từ đây

// Traditional usage 
var max = a 
if (a < b) max = b

// With else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}

// As expression 
val max = if (a > b) a else b

26

Một số trường hợp góc không được đề cập trong câu trả lời khác.

Vì sự xuất hiện của Take If trong Kotlin 1.1 , toán tử ternary a ? b : ccũng có thể được biểu thị như sau:

b.takeIf { a } ?: c

Điều này càng trở nên ngắn hơn trong trường hợp c là null:

b.takeIf { a }

Cũng lưu ý rằng điển hình trong thế giới Java kiểm tra null như value != null ? value : defaultValuedịch trong Kotlin ý thức hệ sang value ?: defaultValue.

Tương tự a != null ? b : ccó thể được dịch sang a?.let { b } ?: c.


6
Làm thế nào là b.takeIf { a } ?: cngắn hơn và dễ đọc hơn if (a) b else c? Toán tử Terneray chắc chắn là một tính năng bị thiếu trong Kotlin vì tên biến và điều kiện có thể dài và khiến bạn chia dòng là xấu
Javad Sadeqzadeh

1
Cũng cần lưu ý rằng takeIfluôn luôn đánh giá trường hợp thực (ở đây a). Biểu thức đó không chỉ có thể được tính toán một cách vô ích nếu atình cờ là sai, mà bạn không thể hưởng lợi từ các diễn viên thông minh à la if (a is Int) { a + 3 }.
TheOperator

@TheOperator, sai rồi. { a }là một lambda đánh giá lười biếng.
Vadzim

1
Tôi đã viết sai, nên "luôn luôn đánh giá trường hợp thật (ở đây b)". Nhưng thậm chí { a }, trong khi lười biếng, phải được đánh giá để xác định kết quả của biểu thức.
TheOperator

24

Hãy xem các tài liệu :

Trong Kotlin, nếu là một biểu thức, tức là nó trả về một giá trị. Do đó, không có toán tử ternary (điều kiện? Sau đó: khác), bởi vì bình thường nếu hoạt động tốt trong vai trò này.


13

Java

int temp = a ? b : c;

Tương đương với Kotlin,

var temp = if (a) b else c

12

NHIỆM VỤ :

Hãy xem xét ví dụ sau:

if (!answer.isSuccessful()) {
    result = "wrong"
} else {
    result = answer.body().string()
}
return result

Chúng ta cần tương đương như sau trong Kotlin:

return (! answer.isSuccessful ()) ? "sai" : answer.body (). string ()


GIẢI PHÁP :

1.a . Bạn có thể sử dụng if-expressiontrong Kotlin:

return if (!answer.isSuccessful()) "wrong" else answer.body().string()

1.b . Nó có thể tốt hơn nhiều nếu bạn lật nó if-expression(hãy làm mà không có not):

return if (answer.isSuccessful()) answer.body().string() else "wrong"

2 . Nhà điều hành Elvis của Kotlin ?:có thể làm một công việc thậm chí còn tốt hơn:

return answer.body()?.string() ?: "wrong"

3 . Hoặc sử dụng một Extension functioncho Answerlớp tương ứng :

fun Answer.bodyOrNull(): Body? = if (isSuccessful()) body() else null

4 . Sử dụng Extension functionbạn có thể giảm mã nhờ Elvis operator:

return answer.bodyOrNull()?.string() ?: "wrong"

5 . Hoặc chỉ sử dụng whentoán tử:

when (!answer.isSuccessful()) {
    parseInt(str) -> result = "wrong"
    else -> result = answer.body().string()
}

Hi vọng điêu nay co ich.


11

khi thay thế toán tử chuyển đổi của các ngôn ngữ giống như C. Ở dạng đơn giản nhất, nó trông như thế này

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}

3
Đúng, nhưng ví dụ bạn hiển thị có whendưới dạng một tuyên bố, không phải là một biểu thức. Một so sánh phù hợp hơn với các biểu thức điều kiện ternary sẽ là mỗi nhánh trả về một giá trị, sao cho toàn bộ khi biểu thức ước lượng thành một giá trị (như xảy ra với các điều kiện ternary).
vẽ Noakes

9

Không có nhà điều hành ternary trong Kotlin. Có vẻ như có vấn đề ở cái nhìn đầu tiên. Nhưng nghĩ rằng chúng ta có thể làm điều đó với nội tuyến nếu câu lệnh khác bởi vì đây là biểu thức ở đây. Đơn giản là chúng ta phải làm -

var number = if(n>0) "Positive" else "Negetive"

Ở đây chúng ta có thể khác nếu chặn quá nhiều như chúng ta cần. Giống-

var number = if(n>0) "Positive" else if(n<0) "Negative" else "Zero"

Vì vậy, dòng này là rất đơn giản và dễ đọc hơn so với toán tử ternary. Khi chúng ta sử dụng nhiều hơn một toán tử ternary trong java thì có vẻ khủng khiếp. Nhưng ở đây chúng tôi có một cú pháp rõ ràng. thậm chí chúng ta có thể viết nó trong nhiều dòng quá.


9

Bạn có thể sử dụng var a= if (a) b else cthay cho toán tử ternary.

Một khái niệm hay khác về kotlin là Elvis operater. Bạn không cần phải kiểm tra null mỗi lần.

val l = b?.length ?: -1

Điều này sẽ trả về độ dài nếu b không null nếu không nó thực thi câu lệnh bên phải.


7

như Drew Noakes đã trích dẫn, kotlin sử dụng câu lệnh if làm biểu thức, do đó Toán tử điều kiện Ternary không còn cần thiết nữa,

nhưng với chức năng mở rộng và nạp chồng, bạn có thể tự thực hiện, đây là một ví dụ

infix fun <T> Boolean.then(value: T?) = TernaryExpression(this, value)

class TernaryExpression<out T>(val flag: Boolean, val truly: T?) {
    infix fun <T> or(falsy: T?) = if (flag) truly else falsy
}

sau đó sử dụng nó như thế này

val grade = 90
val clazz = (grade > 80) then "A" or "B"

Có thể xóa <T> better infix fun hoặc (falsy: T?) = If (flag) thật sự khác falsy
solo

1
Nhưng thêm <T> có thể làm cho nó hoạt động: (lớp> 80) rồi null hoặc "B"
solo

Điều này thật tuyệt, tôi sẽ sử dụng nó: P Nhưng xin lưu ý rằng, trừ khi tôi nhầm, nó sẽ gây ra sự phân bổ đối tượng mỗi lần nó được gọi. Không phải là một thỏa thuận lớn, nhưng đáng để biết nó không phải là một sự trừu tượng chi phí bằng không.
Adam

6

Một cách tiếp cận thú vị khác là sử dụng when:

when(a) {
  true -> b
  false -> b
}

Có thể khá tiện dụng trong một số tình huống phức tạp hơn. Và thành thật mà nói, nó dễ đọc đối với tôi hơnif ... else ...


6

Bạn có thể làm điều đó theo nhiều cách trong Kotlin

  1. Sử dụng nếu

    if(a) b else c
  2. Sử dụng khi

    when (a) { 
        true -> print("value b") 
        false -> print("value c") 
        else -> {  
            print("default return in any other case") 
        } 
    }
  3. An toàn Null

    val a = b ?: c

5

Không có hoạt động ternary trong Kotlin, nhưng có một số cách thú vị để làm việc xung quanh đó. Như những người khác đã chỉ ra, một bản dịch trực tiếp sang Kotlin sẽ như thế này:

val x = if (condition) result1 else result2

Nhưng, cá nhân, tôi nghĩ rằng có thể có một chút lộn xộn và khó đọc. Có một số tùy chọn khác được xây dựng trong thư viện. Bạn có thể sử dụng Take If {} với toán tử elvis:

val x = result1.takeIf { condition } ?: result2

Điều đang xảy ra là lệnh Take If {} trả về kết quả1 hoặc null của bạn và toán tử elvis xử lý tùy chọn null. Có một số tùy chọn bổ sung, ví dụ: TakeUnless {}:

val x = result1.takeUnless { condition } ?: result2

Ngôn ngữ rất rõ ràng, bạn biết những gì đang làm.

Nếu đó là một điều kiện thường được sử dụng, bạn cũng có thể làm điều gì đó thú vị như sử dụng phương thức mở rộng nội tuyến. Ví dụ, giả sử chúng tôi muốn theo dõi điểm số trò chơi dưới dạng Int, và chúng tôi muốn luôn trả về 0 nếu không đáp ứng một điều kiện nhất định:

inline fun Int.zeroIfFalse(func: () -> Boolean) : Int = if (!func.invoke()) 0 else this     

Ok, điều đó có vẻ xấu. Nhưng hãy xem nó trông như thế nào khi nó được sử dụng:

var score = 0
val twoPointer = 2
val threePointer = 3

score += twoPointer.zeroIfFalse { scoreCondition } 
score += threePointer.zeroIfFalse { scoreCondition } 

Như bạn có thể thấy, Kotlin cung cấp rất nhiều tính linh hoạt trong cách bạn chọn để thể hiện mã của mình. Có vô số biến thể của các ví dụ của tôi và có lẽ là những cách tôi chưa từng khám phá. Tôi hi vọng cái này giúp được!


takeIflà lựa chọn yêu thích của tôi thực sự, rất thanh lịch.
Javier Mendonça

4

Hãy nhớ toán tử Ternarytoán tử Elvis giữ các ý nghĩa riêng biệt trong Kotlin không giống như trong nhiều ngôn ngữ phổ biến. Làm expression? value1: value2sẽ cung cấp cho bạn những từ xấu của trình biên dịch Kotlin , không giống như bất kỳ ngôn ngữ nào khác vì không có toán tử tạm thời trong Kotlin như được đề cập trong các tài liệu chính thức . Lý do là các câu lệnh if, when và try-Catch tự trả về các giá trị.

Vì vậy, làm expression? value1: value2có thể được thay thế bởi

val max = if (a> b) print ("Chọn a") khác in ("Chọn b")

Các nhà điều hành Elvis rằng Kotlin có, chỉ hoạt động trong trường hợp nullable biến cũ .:

Nếu tôi làm một cái gì đó như value3 = value1 ?: value2sau đó nếu value1null thì value2 sẽ được trả về nếu không value1 sẽ được trả về.

Một sự hiểu biết rõ ràng hơn có thể đạt được từ những câu trả lời này .


3

Bạn có thể sử dụng ifbiểu thức cho điều này trong Kotlin. Trong Kotlin iflà một biểu thức có giá trị kết quả. Vì vậy, trong Kotlin chúng ta có thể viết

fun max(a: Int, b: Int) = if (a > b) a else b

và trong Java chúng ta có thể đạt được điều tương tự nhưng với mã lớn hơn

int max(int a, int b) {
return a > b ? a : b
}

2

Nếu bạn không sử dụng ký hiệu chuẩn nào, bạn cũng có thể tạo / mô phỏng nó bằng infix với một cái gì đó như thế này:

tạo một lớp để giữ mục tiêu và kết quả của bạn:

data class Ternary<T>(val target: T, val result: Boolean)

tạo một số hàm infix để mô phỏng thao tác ternary

infix fun <T> Boolean.then(target: T): Ternary<T> {
    return Ternary(target, this)
}

infix fun <T> Ternary<T>.or(target: T): T {
    return if (this.result) this.target else target
}

Sau đó, bạn sẽ có thể sử dụng nó như thế này:

val collection: List<Int> = mutableListOf(1, 2, 3, 4)

var exampleOne = collection.isEmpty() then "yes" or "no"
var exampleTwo = (collection.isNotEmpty() && collection.contains(2)) then "yes" or "no"
var exampleThree = collection.contains(1) then "yes" or "no"

Để có nó hoàn toàn tương đương với một toán tử ternary thực tế, các giá trị đích cũng có thể là lambda cung cấp T
Old Man of Aran

1

Một cách tiếp cận ngắn khác để sử dụng

val value : String = "Kotlin"

value ?: ""

Ở đây kotlin tự kiểm tra giá trị null và nếu nó là null thì nó chuyển giá trị chuỗi rỗng.


1

Tại sao người ta sẽ sử dụng một cái gì đó như thế này:

when(a) {
  true -> b
  false -> b
}

khi bạn thực sự có thể sử dụng một cái gì đó như thế này ( alà boolean trong trường hợp này):

when {
  a -> b
  else -> b
}

1
Bởi vì cái đầu tiên rõ ràng về mặt ngữ nghĩa và dễ hiểu đối với người khác đọc nó ngay cả khi họ không quen thuộc với w / Kotlin, trong khi cái thứ hai thì không.
mc01

1
Chà, bạn đã hiểu rõ, tuy nhiên tôi không thể hiểu tại sao các nhà phát triển của Kotlin không giới thiệu biểu thức tạm thời
ZZ 5

Tôi nghĩ rằng ? and :mâu thuẫn với khai báo nullable / type hơn là kiểm tra kiểu. Ngoài ra tôi không thấy bất kỳ lý do. Tôi nghĩ rằng ai đó chắc chắn đã đặt một số suy nghĩ, nếu có kiểm tra điều kiện if-if nội tuyến. Hãy chờ xem các phiên bản trong tương lai.
bh4r4

1

Khi làm việc với áp dụng (), hãy để có vẻ rất tiện dụng khi xử lý các hoạt động ternary, vì nó thanh lịch hơn và cung cấp cho bạn phòng

val columns: List<String> = ...
val band = Band().apply {
    name = columns[0]
    album = columns[1]
    year = columns[2].takeIf { it.isNotEmpty() }?.let { it.toInt() } ?: 0
}

0

Với các hàm infix sau đây, tôi có thể bao quát nhiều trường hợp sử dụng phổ biến gần giống như cách nó có thể được thực hiện trong Python:

class TestKotlinTernaryConditionalOperator {

    @Test
    fun testAndOrInfixFunctions() {
        Assertions.assertThat(true and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat(false and "yes" or "no").isEqualTo("no")

        Assertions.assertThat("A" and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat("" and "yes" or "no").isEqualTo("no")

        Assertions.assertThat(1 and "yes" or "no").isEqualTo("yes")
        Assertions.assertThat(0 and "yes" or "no").isEqualTo("no")

        Assertions.assertThat(Date() and "yes" or "no").isEqualTo("yes")
        @Suppress("CAST_NEVER_SUCCEEDS")
        Assertions.assertThat(null as Date? and "yes" or "no").isEqualTo("no")
    }
}

infix fun <E> Boolean?.and(other: E?): E? = if (this == true) other else null
infix fun <E> CharSequence?.and(other: E?): E? = if (!(this ?: "").isEmpty()) other else null
infix fun <E> Number?.and(other: E?): E? = if (this?.toInt() ?: 0 != 0) other else null
infix fun <E> Any?.and(other: E?): E? = if (this != null) other else null
infix fun <E> E?.or(other: E?): E? = this ?: other

0

Không có toán tử ternary trong Kotlin, đóng nhất là hai trường hợp dưới đây,

  • Nếu khác như tuyên bố biểu thức

val a = true if(a) print("A is true") else print("A is false")

  • Toán tử Elvis

Nếu biểu thức ở bên trái của ?: Không phải là null, toán tử elvis trả về nó, nếu không nó sẽ trả lại biểu thức ở bên phải. Lưu ý rằng biểu thức phía bên phải chỉ được ước tính nếu phía bên trái là null.

 val name = node.getName() ?: throw IllegalArgumentException("name expected")

Tài liệu tham khảo


0

ví dụ: var Energy: Int = data? .get (vị trí) ?. năng lượng? .toInt () ?: 0

Trong kotlin nếu bạn đang sử dụng ?: Nó sẽ hoạt động như thế nào nếu câu lệnh sẽ trả về null sau đó ?: 0 sẽ mất 0 hoặc bất cứ điều gì bạn có viết bên này.


-1

Trong Kotlin, bạn có thể sử dụng thao tác ternary như thế này: val x = if(a) "add b" else "add c"


1
Câu hỏi này đã được trả lời đủ, và chưa được cập nhật gần đây. Bây giờ không cần phải đăng một câu trả lời khác không khác với những câu trả lời trước đó.
Headcracker

-2

Sau một số nghiên cứu về các ý tưởng khác, tôi đã nhận được toán tử ternary sau:

infix fun <T : Any> Boolean.yes(trueValue: T): T? = if (this) trueValue else null
infix fun <T : Any> T?.no(falseValue: T): T = this ?: falseValue

Ví dụ (chạy ở đây ):

fun main() {
    run {
        val cond = true
        val result = cond yes "True!" no "False!"
        println("ternary test($cond): $result")
    }
    run {
        val cond = false
        val result = cond yes "True!" no "False!"
        println("ternary test($cond): $result")
    }
}

Phiên bản này trôi chảy và không xung đột với toán tử hợp nhất null.


Đây là loại tương tự như câu trả lời lệch lạc nơi nó được đặt tên thenthay vì yes.
Ry-

@Ry có, và tôi không chắc họ có phải là cùng một người hay không nhưng ý tưởng sử dụng các phương thức infix với các tùy chọn xuất phát từ diễn đàn Kotlin. Điều tôi chưa từng thấy là phương pháp 'không' mà tôi đã nghĩ ra vì tôi thấy việc sử dụng nội tuyến của toán tử kết hợp null gây nhầm lẫn bởi vì dấu hỏi nằm sau 'giá trị' thay vì điều kiện như trong hầu hết các ngôn ngữ.
Bryan W. Wagner
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.