2014-11-01 21 views
5

Sto cercando di capire per comprensioni a Scala, e ho un sacco di esempi che ho sorta di capire ...Scala() vs per {}

Una cosa che sto attraversando un periodo difficile capire è per() vs per {}. Ho provato entrambi, e sembra di poter fare una cosa in una, ma si rompe nell'altra.

Ad esempio, questa non funziona:

def encode(number: String): Set[List[String]] = 
    if (number.isEmpty) Set(List()) 
    else { 
    for (
     split <- 1 to number.length 
     word <- wordsForNum(number take split) 
     rest <- encode(number drop split) 
    ) yield word :: rest 
    }.toSet 

Tuttavia, se si cambia a {}, lo fa compilare:

def encode(number: String): Set[List[String]] = 
    if (number.isEmpty) Set(List()) 
    else { 
    for { 
     split <- 1 to number.length 
     word <- wordsForNum(number take split) 
     rest <- encode(number drop split) 
    } yield word :: rest 
    }.toSet         

Questi esempi sono da una classe Coursera Sono prendendo. Il professore non ha menzionato il "perché" nel video & mi stavo chiedendo se qualcun altro lo sa.

Grazie!

+0

Grazie per le risposte davvero approfondite - non ho la necessità di collegare {} con la multipla vs esempi linea singola I stava lavorando. – anonygrits

risposta

7

dalla sintassi nelle specifiche, potrebbe sembrare che parentesi e le parentesi sono intercambiabili:

http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#for-comprehensions-and-for-loops

ma perché i generatori sono separati da semifinale, le seguenti regole nel calcio :

http://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html#newline-characters

aver letto e compreso che la sezione in passato, da cui vagamente la sostanza che newlines sono abilitati nelle parentesi, vale a dire , un carattere di nuova riga viene preso come nl che funge da semi.

Quindi è possibile inserire i generatori su righe separate anziché utilizzare il punto e virgola.

Questa è la normale "deduzione punto e virgola" che consente di non scrivere il punto e virgola come terminatori di istruzioni. Così la nuova riga nel mezzo del generatore non è preso come un semi, per esempio:

scala> for (c <- 
    | List(1,2,3) 
    |) yield c+1 
res0: List[Int] = List(2, 3, 4) 

scala> for { c <- 
    | List(1,2,3) 
    | i = c+1 
    | } yield i 
res1: List[Int] = List(2, 3, 4) 
4

In Scala() sono solitamente per quando si dispone di una sola istruzione. Qualcosa di simile avrebbe funzionato:

def encode(number: String): Set[Int] = 
    if (number.isEmpty) Set() 
    else { 
    for (
     split <- 1 to number.length // Only one statement in the comprehension 
    ) split 
    }.toSet 

aggiungere un altro e sarebbe riuscire a compilare. Lo stesso vale per la mappa per esempio

OK

List(1,2,3).map(number => 
    number.toString 
) 

Non OK (devono usare le parentesi graffe)

List(1,2,3).map(number => 
    println("Hello world") 
    number.toString 
) 

perché. Non ho idea :)

+0

Non mi ero mai reso conto che le multi-linee richiedessero {} prima. Bella presa. – javadba

+1

@javadba Alcune persone (odersky) mettono sempre le parentesi su espressioni multilinea, altre (paulp) preferiscono parenti attorno a un singolo expr che sembra essere multilinea. 'def f = (if (c) x else y)' –

+0

@ som-snytt thx per il puntatore. il parentesi graffa sta confondendo 2 me. – javadba