2013-06-13 23 views
9

http://woss.name/2012/04/02/retrieving-bigdecimals-from-a-database-with-anorm-scala/Co oznacza tylda (~) w tym przykładzie Scali?

object Site { 
    val allFieldsParser = { 
    get[Pk[Long]]("sites.id") ~  // Help me parse this syntax 
    get[String]("sites.name") ~ 
    get[BigDecimal]("sites.latitude") ~ 
    get[BigDecimal]("sites.longitude") map { 
     case id ~ name ~ latitude ~ longitude => 
     Site(id, name, latitude, longitude) 
    } 
    } 

    def findAll(): Seq[Site] = { 
    DB.withConnection { implicit connection => 
     SQL("SELECT * FROM sites").as(Site.allFieldsParser *) 
    } 
    } 
} 
+2

Ta notacja została wyprowadzona z kombinatorów parsera. Proszę zobaczyć http://stackoverflow.com/questions/6818390/understanding-the-tilde-in-scalas-parser-combinators W skrócie, możesz mentalnie zastąpić '~' '&', więc taka struktura będzie wyglądać jak wzór (wiesz, jak wzór w regex). Definiujesz reprezentację wysokiego poziomu, używając konkretnych części (połączonych w stałą strukturę z ~), a następnie parser albo sukcesem, a twoja struktura jest zgodna z twoim schematem, albo kończy się niepowodzeniem. Na przykład, aby dopasować wyrażenie algebraiczne, można napisać coś w stylu 'Numer ~ Operacja ~ Liczba ...' –

+0

@ om-nom-nom Dlaczego więc odpowiedziałeś w komentarzu? –

+1

@ DanielC.Sobral, ponieważ nie jestem pewien, czy pytanie dotyczy technicznej implementacji (co zostało już wyjaśnione przez gzm0), czy też o rzeczach semantycznych. –

Odpowiedz

21

W przykładzie ~ jest używany w dwóch różnych sposobów oznaczać dwie różne rzeczy. W pierwszej części masz

get[Pk[Long]]("sites.id") ~  // Help me parse this syntax 
get[String]("sites.name") ~ 
get[BigDecimal]("sites.latitude") ~ 

itd. Jak już wspomniano, jest to metoda tylko inwokacja, jest taka sama jak

get[Pk[Long]]("sites.id").~(get[String]("sites.name").~(... 

Możesz zajrzeć the definition of this method in the anorm source. Jest to metoda na RowParser[A] (parsera, że ​​analizuje się A, który odbywa się RowParser[B] (parser, który przetwarza B) i zwraca parser który przetwarza A ~ B. Ten A ~ B to drugie znaczenie dla ~. To jest teraz nie odnosząc sposobu, ale do case class defined in the same file here.

case class ~[+A, +B](_1: A, _2: B) 

to tylko przewrotny sposób odnoszenia się do klasy ~[A,B]. na poziomie typu, gdy masz typ konstruktora dwóch argumentów, można użyć nazwy klasa w notacji infiksowej. To nie jest nic specjalnego w stosunku do ~, działałoby z dowolnymi dwoma konstruktor typu argumentu. Jeśli masz trait Foo[A,B], możesz odwołać się do tego jako A Foo B. Analogicznie, w wzór dopasowanie, zmienne a i b może być związany za pomocą składni a Foo b, który jest określany jako wzór Infix operacji w części 8.1.10 z language specification.

W drugiej części swojego przykład masz:

case id ~ name ~ latitude ~ longitude => 

To jest wzorzec dopasowania na tych ~ przypadków clases będących wynikiem prowadzenia parse skonstruowano powyżej. Tak naprawdę jest to po prostu ładniejszy sposób pisania:

case ~(~(~(id, name), latitude), longitude) => 
+0

Dzięki za dokładną odpowiedź. – ripper234

5

W Scala

a ~ b 

oznacza

a.~(b) 

Więc to wywołuje metodę ~ na a i daje b jako argument. Należy również zauważyć, że każdy operator, który nie kończy się na :, jest skojarzony lewostronnie.

Twój przykład revisited byłoby:

get[Pk[Long]]("sites.id").~( // Help me parse this syntax 
get[String]("sites.name").~(
get[BigDecimal]("sites.latitude").~(
get[BigDecimal]("sites.longitude")))) map { 
    case id ~ name ~ latitude ~ longitude => 
    Site(id, name, latitude, longitude) 
} 
+1

Bardziej ogólnie, "cokolwiek b" oznacza "a.whatever (b)" (z wyjątkiem niektórych słów kluczowych, operatorów pierwotnych i lewego asocjacyjnego wskaźnika, o którym już wspomniałeś). –