Каковы границы контекста и представления Scala?

простым способом, каковы границы контекста и представления и в чем разница между ними?

несколько простых примеров будет слишком большой!

1 ответов


я думал, что это уже было задано, но, если это так,вопрос не очевиден в" связанной " панели. Итак, вот оно:

что такое граница представления?

A просмотр bound был введен механизм в Scala, чтобы включить использование некоторого типа A как будто это был какой-то тип B. Типичный синтаксис такой:

def f[A <% B](a: A) = a.bMethod

другими словами, A должно иметь неявное преобразование в B доступно, так что один могу позвонить B методы объекта типа A. Наиболее распространенное использование границ представления в стандартной библиотеке (во всяком случае, до Scala 2.8.0) - это Ordered, например:

def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b

потому что можно преобразовать A на Ordered[A], а потому Ordered[A] определяет способ <(other: A): Boolean, я могу использовать выражение a < b.

помните, что границы просмотра устарели, вы должны избегать их.

что такое контекст Связаны?

контекст, границы были введены в Scala 2.8.0, и обычно используются с так называемым тип класса шаблон, шаблон кода, который эмулирует функциональность, предоставляемую классами типов Haskell, хотя и более подробным образом.

в то время как граница представления может использоваться с простыми типами (например,A <% String), контекстная привязка требует параметризованного типа, например Ordered[A] выше, но в отличие от String.

A контекстная привязка описывает неявное стоимостью, вместо неявногопреобразование. Он используется для объявления, что для некоторого типа A, существует неявное значение типа B[A] доступен. Синтаксис выглядит так:

def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]

это более запутанно, чем вид, связанный, потому что не сразу понятно, как его использовать. Общий пример использования в Scala:

def f[A : ClassManifest](n: Int) = new Array[A](n)

An Array инициализация на a параметризованный тип требует ClassManifest быть доступным по тайным причинам, связанным с типом стирания и не стираемым характером массивов.

другой очень распространенный пример в библиотеке немного сложнее:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

здесь implicitly используется для повторного использования неявного значения, которое мы хотим, одного из типа Ordering[A], что класс определяет метод compare(a: A, b: A): Int.

мы увидим другой способ сделать это ниже.

как границы и контекст представления Границы реализованы?

неудивительно, что как границы представления, так и границы контекста реализуются с неявными параметрами, учитывая их определение. На самом деле синтаксис, который я показал, - это синтаксические сахара для того, что действительно происходит. Смотрите ниже, как они де-сахар:

def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod

def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)

поэтому, естественно, можно написать их в полном синтаксисе, что особенно полезно для границ контекста:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)

для чего используются границы просмотра?

посмотреть рамки используются в основном, чтобы воспользоваться сутенер моя библиотека pattern, через который" добавляет " методы к существующему классу, в ситуациях, когда вы хотите каким-то образом вернуть исходный тип. Если вам не нужно возвращать этот тип каким-либо образом, вам не нужна привязка представления.

классический пример использования привязки просмотра-обработка Ordered. Обратите внимание, что Int не Ordered, например, Хотя существует неявное преобразование. Пример ранее данный нуждается в привязке представления, потому что он возвращает не преобразованный тип:

def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b

этот пример не будет работать без границ. Однако, если я должен был вернуть другой тип, то мне больше не нужен привязанный вид:

def f[A](a: Ordered[A], b: A): Boolean = a < b

преобразование здесь (при необходимости) происходит до того, как я передам параметр в f, так что f не нужно об этом знать.

кроме того Ordered, наиболее распространенным использованием из библиотеки является обработка String и Array, которые являются классами Java, как будто они были коллекциями Scala. Например:

def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b

если попытаться сделать это без границ просмотра, возвращаемый тип String будет WrappedString (Scala 2.8), и аналогично для Array.

то же самое происходит, даже если тип используется только в качестве параметра, тип возвращаемого типа:

def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted

для чего используются границы контекста?

границы контекста в основном используются в том, что стало известно как шаблон typeclass, как ссылка на классы типов Haskell. В принципе, этот шаблон реализует альтернативу наследованию, делая функциональность доступной через своего рода неявный шаблон адаптера.

классический пример-Scala 2.8 Ordering, который заменил Ordered по всей библиотеке Scala. Использование:

def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b

хотя вы обычно увидите, что написано так:

def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
    import ord.mkOrderingOps
    if (a < b) a else b
}

которые используют некоторые неявные преобразования внутри Ordering которые включают традиционный стиль оператора. Другим примером в Scala 2.8 является Numeric:

def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)

более сложным примером является использование новой коллекции CanBuildFrom, но об этом уже есть очень длинный ответ, поэтому я буду избегать его здесь. И, как упоминалось ранее, есть ClassManifest использование, которое требуется для инициализации новых массивов без конкретных типов.

контекст связан с шаблоном typeclass гораздо больше вероятно, будут использоваться вашими собственными классами, поскольку они позволяют разделять проблемы, тогда как границ просмотра можно избежать в вашем собственном коде хорошим дизайном (он используется в основном для обхода чужого дизайна).

хотя это было возможно в течение длительного времени, использование границ контекста действительно взлетело в 2010 году и теперь в некоторой степени найдено в большинстве наиболее важных библиотек и фреймворков Scala. Наиболее экстремальным примером его использования, однако, является библиотека Scalaz, которая приносит много власти Хаскелла для Скалы. Я рекомендую прочитать о шаблонах typeclass, чтобы узнать больше обо всех способах его использования.

редактировать

связанные вопросы, представляющие интерес: