2017-06-16 22 views
21

Zgodnie z Kotlin docs,?. operator reprezentuje "bezpieczne połączenie", co oznacza, że ​​jeśli jest używany w łańcuchu wywołań metod, cały łańcuch zwróci wartość null, jeśli wartość tego, na czym jest używana, jest zerowa.Co robi?. znaczy w Kotlin, gdy jest używany po lewej stronie zadania?

Ale co z tym, czy jest używany po lewej stronie zadania? Ponieważ lewa strona nie jest stroną, która "zwraca" coś, wydaje się, że prawdopodobnie ma ona inny efekt. Oto przykład tego, co mówię:

val myObj = SomeObj() 
myObj?.property = SomeClass.someFunc() // What does ?. do in this context? 

Odpowiedz

27

Oznacza to, że jeśli jeden z bezpiecznych połączeń z lewej strony nie powiedzie się (tzn jego odbiornik jest null), wówczas cała cesja jest pomijany, a wyrażenie po prawej stronie nie jest w ogóle oceniane.

val nullable: Container? = null 
nullable?.x = f() // f is not called 

(runnable demo)

+0

Jest to interesujące, ponieważ w przypadku, gdy przypisujesz coś do wartości opartej na samym sobie, nadal musisz używać go po prawej stronie, aby uniknąć błędu kompilatora. (np. myObj? .property = myObj? .property + 1) – Sonofblip

+4

@Sonofblip, jest inny powód: w środowisku wielowątkowym (w którym znajduje się JVM), zmienna globalna 'myObj' może zostać ponownie przypisana między czekiem po lewej stronie i ocena 'myObj? .property' po prawej stronie. Musisz to sprawdzić ponownie. – hotkey

+0

@ skeykey, pierwsze up-vote. ale nie musi to sprawdzać ponownie w wielu wątkach, ponieważ kotlina kopiuje odniesienie do innej zmiennej. –

2

widzę zabawy pytanie & odpowiedź w Kotlin właśnie teraz. Nawet jeśli odpowiedź jest bardzo przyjemna, ale chcę ją wyjaśnić bardziej szczegółowo.

Wyrażenie przyporządkowanie poniżej

myObj?.property = SomeClass.someFunc() 

przekształca się kodu binarnego Java przez Kolin jak poniżej:

val it = myObj; 

if(it != null){ 
    it.property = SomeClass.someFunc(); 
} 

więc nie ma problemu z wielu wątków. Nadal działa dobrze i przetestowałem go na github. Ale spowoduje to problem Thread Interference, co oznacza, że ​​zmodyfikuje property na różnych odniesieniach po zmianie myObj.

wyjątkiem wyrażenia przypisania mogą być zwarte, inni też mogą być zwarcie. Na przykład:

val array:Array<Any>? = null; 

// v--- short-circuited 
array?.set(0,SomeClass.someFunc()); 
//      ^--- never be called