2017-06-14 15 views
6

Poznaję nowy i bardzo piękny język Kotlin i wszystko wydaje się być bardzo logiczne i spójne. Znalazłem tylko jedną rzecz, która wydaje się arbitralnym wyjątkiem od reguły, niż solidną regułą. Ale może brakuje mi wystarczającej wiedzy na temat głębszych przyczyn tej reguły.zwraca ostatnie wyrażenie w bloku

Wiem, że w instrukcjach i when są bloki kodu, a następnie zwracane jest ostatnie wyrażenie. W kolejnym przykładzie 1 lub 2 są zwracane w zależności od warunku - w naszym przypadku zwraca 1.

val x = if (1 < 2) {println("something"); 1} else {println("something else"); 2} 

Z drugiej strony nie dotyczy to żadnego bloku kodu. Następny wiersz przypisuje y nie do 1, ale do całego bloku kodu jako lambda.

val y = {println("something"); 1} 

Podobnie w treści funkcji ostatnie wyrażenie nie jest zwracane. To nawet nie kompiluje.

fun z() : Int { 
    println("something") 
    1 
} 

Jaka jest dokładnie reguła? Czy rzeczywiście jest tak arbitralny: jeśli w instrukcji if-else lub when, która jest używana jako wyrażenie, znajduje się blok kodu, zwracane jest ostatnie wyrażenie w bloku. W przeciwnym razie ostatnie wyrażenie nie zostanie zwrócone do zewnętrznego zakresu. Czy może czegoś brakuje?

Odpowiedz

4

nie zrozumiałeś nawiasy nawiasy {}, gdy wokół z wszystkimi flow-control rachunku to tylko blok, na przykład:

if (condition) { //block here 
} 

KIEDY{} deklaruje osobno to lambda wyrażenie na przykład:

val lambda:() -> Int = { 1 }; // lambda 

KIEDY chcesz zwrócić lambda w if-else wyrażenie, należy podwoić nawiasy nawiasy {} lub używając nawiasów () odróżnić blokui lambda ekspresji lub dokonać {} jako lambda jawnie, na przykład:

val lambda1:() -> Int = if (condition) { { 1 } } else { { 2 } }; 
val lambda2:() -> Int = if (condition) ({ 1 }) else ({ 2 }); 
val lambda3:() -> Int = if (condition) { -> 1 } else { -> 2 }; 

Jeżeli funkcja nie zwraca żadnej wartości użytkowej, jego typ zwracany jest Unit. Unit to typ z tylko jedną wartością - Unit. Ta wartość nie musi być zwracana jawnie.

Z drugiej strony, wspólnyfunction musi mieć wyraźny return oświadczenie, jeśli jego typ zwracany jeśli nie Unit:

fun z(): Int { return 1; } 

Kolejna sprawa to powrót funkcja Nothing The return stwierdzenie don Zezwolono w ogóle, ponieważ nie można utworzyć instancji Nothing, na przykład:

fun nothing(): Nothing { 
    return ?;// a compile error raising 
} 

KIEDY funkcja ma tylko jeden wyraz wtedy można za pomocą single-expression function zamiast, na przykład:

fun z() = 1; 
+1

Tak, to jest chyba to, co mam na myśli moim komentarzem. '{}' ma trzy (lub jeszcze więcej? Czy brakuje mi niektórych?) różnych ról - może to być blok w instrukcji sterowania przepływem lub może to być lambda lub może być ciałem funkcji. W przypadku wszystkich tych przypadków obowiązują inne zasady. Nie chcę narzekać ani narzekać, będę musiał wziąć to, jak jest. Ale wydaje mi się to nieco niespójną wadą projektowania językowego nienagannego języka. –

+0

@ V.K. tak jest. masz rację. –

+1

Mój styl kodowania na to pytanie jest taki, że postaram się unikać bloków w instrukcjach kontroli przepływu, gdy są one używane jako wyrażenia. Pochodzę z dziedzin C++ i Python i nie ma to jak "zwróć ostatnie wyrażenie w bloku", więc użyję wyrażenia "if" lub "when" jako wyrażenia tylko wtedy, gdy zwracane wyrażenia są trywialne (bez bloku), np. 'a = if (x) y else z'. W przeciwnym razie użyję pełnej składni "if (x) {println (" something "); a = y} else {println ("coś innego"); a = z} 'jak wiemy z innych języków. –

2

istnieje różnica pomiędzy blokiem lambda i tylko „normalne” bloku, w przypadku „y "jest tylko lambda, która musi być wykonana, aby uzyskać wartość zwracana:

val block:() -> Int = { 5 } 
val five: Int = { 5 }() 
val anotherFive = block() 

Więc jeśli chcesz blok, który działa jako lambda, można utworzyć lambda i wykonać go od razu z«()» . W ten sposób Twoja funkcja „Z” będzie skompilować tak:

fun z() : Int = { println("something") 1 }()

(które, oczywiście, nie ma sensu i nie jest bardzo wydajne)

Powiązane problemy