Каковы границы контекста и представления 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, чтобы узнать больше обо всех способах его использования.
редактировать
связанные вопросы, представляющие интерес: