Что делать <: <, <% <, и =: = означает в Scala 2.8, а где они документированы?

StackOverflow https://stackoverflow.com/questions/3427345

Вопрос

Я вижу в документах API для Предеф что они подклассы родового типа функции (из) =>, но это все, что он говорит. Хм, что? Может быть, есть где-то документация, но поисковые системы не обрабатывают «имена», как «<: <» очень хорошо, поэтому я не смог его найти.

Последующий вопрос: когда я должен использовать эти функции / классы / классы, а почему?

Это было полезно?

Решение

Это называется Обобщенные ограничения типа. Отказ Они позволяют вам, из-за типового параметризованного класса или черта, чтобы дополнительно ограничить один из параметров его типа. Вот пример:

case class Foo[A](a:A) { // 'A' can be substituted with any type
    // getStringLength can only be used if this is a Foo[String]
    def getStringLength(implicit evidence: A =:= String) = a.length
}

Неявный аргумент evidence поставляется компилятором, IFF A является String. Отказ Вы можете думать об этом как об этом как доказательство тот A является String- Сам аргумент не важен, только зная, что он существует. править: ну, технически это на самом деле важно, потому что он представляет неявное преобразование от A к String, что позволяет вам звонить a.length И не иметь компилятора кричать на вас

Теперь я могу использовать это так:

scala> Foo("blah").getStringLength
res6: Int = 4

Но если бы я попробовал использовать его с Foo содержащий что-то кроме String:

scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]

Вы можете прочитать эту ошибку как «не удалось найти доказательства того, что int == string" ... Вот как это должно быть! getStringLength навязывается дальнейшие ограничения на типе A тогда что Foo в целом требуется; А именно, вы можете только вызвать getStringLength на Foo[String]. Отказ Это ограничение применяется при компиляции времени, которое круто!

<:< и <%< Работайте аналогично, но с небольшими вариациями:

  • A =:= B означает, что должен быть точно б
  • A <:< B означает, что должен быть подтип B (аналогично просто Тип ограничения <:)
  • A <%< B означает, что должно быть посмотреть Как B, возможно, через неявное преобразование (аналогично простому ограничению типа <%)

Этот фрагмент @ Retrorrymy - это хорошее объяснение того, как эта вещь используется, и насколько обобщенными ограничениями типа делают это легче сейчас.

Приложение

Чтобы ответить на ваш последующий вопрос, по общему признанию, пример, который я дал, довольно удушают и не явно полезны. Но представьте, используя его, чтобы определить что-то вроде List.sumInts Способ, который добавляет список целых чисел. Вы не хотите, чтобы этот метод был вызван на любой старый List, просто а List[Int]. Отказ Однако List Тип конструктор не может быть настолько ограничен; Вы все еще хотите иметь возможность иметь списки строк, фуро, баров и othorots. Поэтому, поместив обобщенный тип ограничения на sumInts, вы можете убедиться, что Просто этот метод имеет дополнительное ограничение, которое его можно использовать только на List[Int]. Отказ По сути, вы пишете специальный код для определенных видов списков.

Другие советы

Не полный ответ (другие уже ответили на это), я просто хотел отметить следующее, что может лучше понять синтаксис лучше: то, как обычно вы используете эти «операторы», как, например, в примере Pelotom:

def getStringLength(implicit evidence: A =:= String)

использует альтернативу Scala Инфикс синтаксис для операторов типа.

Так, A =:= String такой же как =:=[A, String]=:= это просто класс или черта с неожиданным именем). Обратите внимание, что этот синтаксис также работает с «регулярными» классами, например, вы можете написать:

val a: Tuple2[Int, String] = (1, "one")

как это:

val a: Int Tuple2 String = (1, "one")

Это похоже на два синтаксиса для вызовов метода, «нормально» с . и () и синтаксис оператора.

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

Вот пример. Предположим, вы хотите определить однородную пару, как это:

class Pair[T](val first: T, val second: T)

Теперь вы хотите добавить метод smaller, как это:

def smaller = if (first < second) first else second

Это только работает, если T заказывается. Вы можете ограничить весь класс:

class Pair[T <: Ordered[T]](val first: T, val second: T)

Но это кажется стыдом - можно использовать для класса, когда T не заказывается. С ограничением типа, вы все еще можете определить smaller Метод:

def smaller(implicit ev: T <:< Ordered[T]) = if (first < second) first else second

Это нормально, чтобы мгновенное, скажем, Pair[File], до тех пор, пока вы не звоните smaller в теме.

В случае Option, Ремонт хотел orNull метод, даже если это не имеет смысла для Option[Int]. Отказ Используя ограничение типа, все хорошо. Ты можешь использовать orNull на Option[String], и вы можете сформировать Option[Int] и использовать его, пока вы не звоните orNull в теме. Если вы попытаетесь Some(42).orNull, Вы получаете очаровательное сообщение

 error: Cannot prove that Null <:< Int

Это зависит от того, где они используются. Чаще всего при использовании при объявлении типов неявных параметров они являются классами. Они могут быть объекты тоже в редких случаях. Наконец, они могут быть операторами на Manifest объекты. Они определены внутри scala.Predef В первые два случая, хотя и не особенно хорошо документированы.

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

Что касается вопроса «Когда я должен использовать их?», Ответ - это вы не должны, если вы не знаете, что вы должны. :-) РЕДАКТИРОВАТЬ: Хорошо, хорошо, вот несколько примеров из библиотеки. На Either, у тебя есть:

/**
  * Joins an <code>Either</code> through <code>Right</code>.
  */
 def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C] = this match {
   case Left(a)  => Left(a)
   case Right(b) => b
 }

 /**
  * Joins an <code>Either</code> through <code>Left</code>.
  */
 def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match {
   case Left(a)  => a
   case Right(b) => Right(b)
 }

На Option, у тебя есть:

def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null

Вы найдете некоторые другие примеры на коллекциях.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top