2013-06-13 2 views
9

http://woss.name/2012/04/02/retrieving-bigdecimals-from-a-database-with-anorm-scala/Что означает тильда (~) в этом примере Scala?

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

Эта нотация была получена из комбинаторов парсеров. Пожалуйста, см. Http://stackoverflow.com/questions/6818390/understanding-the-tilde-in-scalas-parser-combinators. Короче говоря, вы можете мысленно заменить '~' на '&', поэтому такая структура будет выглядеть как шаблон (вы знаете, как шаблон в регулярном выражении). Вы определяете представление высокого уровня, используя определенные части (объединенные в сплошную структуру с ~), а затем анализируете либо succedes, и вы получаете структуру по вашей схеме, либо не удается. Например, чтобы соответствовать алгебраическому выражению, можно написать что-то вроде 'Number ~ Operation ~ Number ...' –

+0

@ om-nom-nom Итак, почему вы ответили в комментарии? –

+1

@ DanielC.Sobral, потому что я не уверен, что вопрос о технической реализации (который уже был объяснен gzm0) или о семантическом материале. –

ответ

21

В вашем примере, ~ используется двумя различными способами, чтобы означать две разные вещи. В первой части у вас есть

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

и т.д. Как уже было сказано, это просто вызов метода, это то же самое, как

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

Вы можете посмотреть на the definition of this method in the anorm source. Это метод на RowParser[A] (синтаксический анализатор, который разбирает A, который принимает RowParser[B] (синтаксический анализатор, который анализирует B) и возвращает парсер, который разбирает A ~ B. Это A ~ B является вторым смыслом для ~. Это теперь идет не к способу, но к case class defined in the same file here.

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

Это просто своеобразный способ обращения к классу ~[A,B]. на уровне типа, когда у вас есть конструктор типа в два аргумента, вы можете использовать имя класс в инфиксной нотации. Это не что-то особенное о ~, оно будет работать с любыми двумя конструктор типа аргумента. Если у вас есть trait Foo[A,B], вы можете называть это как A Foo B. Аналогично, в сопоставлении с образцом, переменных a и b может быть связан с использованием синтаксиса a Foo b, который упоминается как инфиксной операции Pattern в разделе 8.1.10 на language specification.

Во второй части вашего примера у вас есть:

case id ~ name ~ latitude ~ longitude => 

Это сопоставление с образцом на этих ~ случае clases, которые являются результатом запуска разобрана вы сконструированный выше. Так что это действительно лучший способ написать:

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

Спасибо за подробный ответ. – ripper234

5

В Scala

a ~ b 

означает

a.~(b) 

Так он вызывает метод ~ на a и дает b в качестве аргумента. Также обратите внимание, что любой оператор, не заканчивающийся :, лево-ассоциативный.

Ваш пример вновь будет:

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

В более общем смысле, 'a any b' означает' a.whatever (b) '(за исключением некоторых ключевых слов, примитивных операторов и левого ассоциативного индикатора, которые вы уже упоминали). –

Смежные вопросы