2012-12-14 14 views
12

Zawsze zastanawiałem się, dlaczego czasami z literałami funkcji możemy zignorować nawias klamrowy nawet dla wielu instrukcji. Aby to zilustrować, składnia literału funkcji multilinii polega na zamknięciu instrukcji za pomocą nawiasów klamrowych. Jak tak,Funkcja Multiline dosłownie jako argumenty w Scala

val fl = (x: Int) => { 
    println("Add 25 to "+x) 
    x + 25 
} 

Jeśli jednak przekazać go do funkcji jednego argumentu, można zignorować wymaganą nawias klamrowy dla funkcji dosłownym.

Więc dla danej funkcji f,

def f(fl: Int => Int) { 
    println("Result is "+ fl(5)) 
} 

Można zadzwonić f(), tak jak to,

f(x=> { 
    println("Add 25 to "+x) 
    x + 25 
}) 
------------------------- 
Add 25 to 5 
Result: 30 

Albo kiedy używasz nawiasów klamrowych zamiast nawias w wywołaniu funkcji, można usuń wewnętrzne nawiasy klamrowe z literału funkcji. Tak więc poniższy kod będzie działał,

Powyższy kod jest bardziej czytelny i zauważam, że wiele przykładów używa tej składni. Czy istnieje jednak jakaś specjalna reguła, którą mogłem pominąć, aby wyjaśnić, dlaczego działa ona zgodnie z zamierzeniami?

Odpowiedz

20

Istnieje tylko kilka prostych reguł składni. Dodatek do specyfikacji jest warty uwagi.

Funkcja literalna lub anonimowa (6.23) będzie wyglądać jak x => Expr lub x => Block w zależności od tego, czy kontekst jest odpowiednio Expr, czy ResultExpr.

Aplikacja funkcji (6.6) będzie wyglądać jak f(Expr, Expr) lub f BlockExpr, tj. f{ Block }. To znaczy, BlockExpr to po prostu sekwencja instrukcji blokowych wewnątrz {...}.

Po wywołaniu f(g), g jest rozszerzeniem, tak jak literałem funkcji, x => Expr. Expr może być BlockExpr, x => { ... }.

Po wywołaniu , f { x => ... } ma literał funkcji w ResultExpr bloku (który jest po prostu sekwencją instrukcji, nie są wymagane żadne nawiasy klamrowe).

Tutaj, to oczywiste, że func anon jest w dolnej części bloku:

scala> def m(x: Int=>Int) = x(5) 
m: (x: Int => Int)Int 

scala> m { 
    | val y = 7 
    | x => // no brace 
    | x+y+1 
    | } 
res0: Int = 13 
+0

To wyjaśnienie szukałem. Oprócz podsekcji podświetlonej specyfikacji można również zapoznać się z sekcją Bloki (6.11), aby lepiej zrozumieć. – jafaeldon

+0

Odpowiedź Geata, nie mogłem tego lepiej wyjaśnić. Wznowiono to. Twoje zdrowie! – wleao

8

Jest to jedna z rzeczy, które sprawiają, że Scala jest piękna.

Prosta odpowiedź na to pytanie brzmi:

nawiasy() są przeznaczone do konstrukcji jednej linii. Na przykład działa to:

def f(fl: Int => Int) { 
    println("Result is " + fl(5)) 
    } 

    f(
    x => 
    x + 25) 

    f(x => x + 25) // single line 

i nawiasy klamrowe {} są przeznaczone do instrukcji wielowierszowych. Na przykład, to działa:

f { 
    x => 
    println("Add 25 to " + x) 
    x + 25 
} 

ale ten kod nie działa:

f ( 
    x => 
    println("Add 25 to " + x) 
    x + 25 
) 

Kompilator narzeka z następującym komunikatem:

wartość X nie jest członkiem Działu możliwa przyczyna: być może brakuje średnika przed wartością x?

Po dodaniu średnika otrzymasz błąd składni spowodowany niedopasowanym nawiasem.

Jeśli spróbujesz to zrobić:

f { x => println("Add 25 to " + x) x + 25 } 

Kompilator będzie wrócić do Ciebie z komunikatem:

value x is not a member of unit 

Rozumiesz, że on próbuje znaleźć x jako członek jednostka. Na przykład:

f { println("Add 25 to " + x).x.+(25) } 

Co jest oczywiście błędne.

Jeśli dodać wewnętrzne szelki kręcone w następujący sposób:

f ( 
    x => { 
    println("Add 25 to " + x) 
    x + 25 
    } 
) 

ta będzie również pracować, ale nadal masz multilinii oświadczenie, które jest sygnalizowane przez korzystanie z klamrami. Zatem kompilator wie, co chcesz, aby najpierw wydrukować, a następnie dodać od 25 do x.

Zostałem ugryziony wcześniej przez te subtelności. Od tamtej pory zwracam uwagę na sposób, w jaki koduję z nimi, ponieważ będziesz kodować i czytać wiele z nich, gdy będziesz głównie używać map, map płaskich, foreów, forów i curry.

Pozdrawiam!

Powiązane problemy