Скобка параметра типа Scala - PullRequest
4 голосов
/ 18 марта 2011

Я знаю trait Foo[T] означает, что T является параметризованным типом. Но иногда я вижу trait Foo[T1,T2] или trait Foo[T1,T2,R], я не могу нигде найти описания значения нескольких типов в скобках типов, не могли бы вы указать мне использование в этом случае? Из того, что я предполагаю, Foo [T1, T2] просто означает, что он определил два параметра типа, он не должен принимать T1 и возвращать T2.

Когда я сегодня прочитал документацию playframework , я снова запутался в этом вопросе. В документации сказано:

BodyParser [A] - это, по сути, Iteratee [Array [Byte], A], что означает, что он получает куски байтов (пока веб-браузер загружает некоторые data) и вычисляет в качестве результата значение типа A.

Это объяснение звучит так, как только параметр типа внутри скобки типа является возвращаемым типом.

Я также помню, что trait Function2 [-T1, -T2, +R] extends AnyRef означает функцию, которая принимает T1 и T2, возвращая R.

Почему они помещают тип возврата в скобки? Означает ли это, что последний параметр в скобках является типом возвращаемого значения? Или они только что определили новый тип R для возвращаемого типа?

Ответы [ 4 ]

7 голосов
/ 24 февраля 2012

Из того, что я предполагаю, Foo [T1, T2] просто означает, что он определил два параметра типа, он не должен принимать T1 и возвращать T2.

* 1005.*

Параметр типа означает не что иное, как «мне нужен любой тип, но мне не интересно знать, что это за конкретный тип», где «I» - программист, который пишет код.Параметры типа могут использоваться как любые другие типы, такие как Int, String или Complex - единственное отличие состоит в том, что они не известны, пока их не используют.

См. Тип Map[A, +B].Когда вы впервые прочитаете это, вы не сможете узнать, для чего предназначены A и B, поэтому вам нужно прочитать документацию:

Карта ключей типа A и значений типа B.

Объясняет типы и их значение.Больше нечего знать или понимать.Они просто два типа.Карту можно назвать чем-то вроде Map[Key, Value], но внутри исходного кода лучше, когда параметры типа имеют только одну или две буквы.Это облегчает различие между параметрами типа и конкретными типами.

Документация определяет, что означает параметр типа.И если нет документации, вы должны взглянуть на источники и найти их значение самостоятельно.Например, вы должны сделать это с Function2 [-T1, -T2, +R].Документация говорит нам только об этом:

Функция 2 параметров.

Хорошо, мы знаем, что два из трех параметров типа являются параметрами, которые ожидает функция, но чтотретий?Мы рассмотрим источники:

def apply (v1: T1, v2: T2): R

Ах, теперь мы знаем, что T1 и T2 являются параметрами, а R является возвращаемым типом.

Параметры типа также можно найти в сигнатурах методов, таких как map:

class List[+A] {
  ..
  def map[B](f: (A) ⇒ B): List[B]
}

Вот как выглядит карта, когда вы ее используетесо списком.A может быть любого типа - это тип элементов, содержащихся в списке.B - другой произвольный тип.Когда вы знаете, что делает карта, тогда вы знаете, что делает B.В противном случае вы должны понимать карту раньше.map ожидает функцию, которая может преобразовать каждый элемент списка в другой элемент.Поскольку вы знаете, что A обозначает элементы Списка, которые вы можете извлечь из себя, B должен быть типа A, преобразуемого в.

Чтобы ответить на все другие ваши вопросы: Это не следуетне может быть сделано в одном ответе.В StackOverflow есть много других вопросов и ответов, которые также могут ответить на ваши вопросы.

Сводка

Когда вы видите некоторые параметры типа, например, в Foo[T1, T2], вы не должны плакать.Подумайте: «Хорошо, у меня есть Foo, который ожидает T1 и T2, и если я хочу знать, что они делают, я должен прочитать документацию или источники».

4 голосов
/ 18 марта 2011

Несколько типов внутри скобки типов означает параметризацию типов для нескольких типов. Взять например

trait Pair[A, B]

Это пара значений, одно из которых имеет тип A, другое имеет тип B.

Обновление:

Я думаю, вы слишком много интерпретируете в семантику параметров типа. Тип, параметризованный несколькими параметрами, - это просто и ничего более. Положение определенного параметра типа в списке параметров типа никоим образом не делает его особенным. В частности, последний параметр в списке параметров типа не обязательно должен обозначать «возвращаемый тип».

Предложение из игровой среды, которое вы цитировали, объясняет семантику параметров типа для этого конкретного типа. Это не обобщает на другие типы. То же самое относится к типам Function: здесь последний параметр типа означает «возвращаемый тип». Это не обязательно относится к другим типам. Тип Pair[A, B] сверху является таким примером. Здесь B - тип второго компонента пары. Здесь вообще нет понятия «тип возврата».

Параметры типа параметризованного типа могут появляться в любом месте внутри определения параметризованного типа, где может появляться «обычный» тип. То есть параметры типа - это просто имена для типов, которые связаны с фактическими типами только тогда, когда создается экземпляр самого параметризованного типа.

Рассмотрим следующее определение класса Tuple:

class Tuple[A, B](a: A, b: B)

Он создается для типа кортежа Int и String, например:

type TupleIntString = Tuple[Int, String]

Что, по сути, совпадает с

class TupleIntString(a: Int, b: String)     

Для получения официального источника проверьте Scala Language Specification . В частности, в разделе 3.4 «Базовые типы и определения элементов» в разделе 1. 4-й пункт маркированного списка говорится: «Базовые типы параметризованного типа C [T_1, ..., T_n] являются базовыми типами типа C, где каждое вхождение параметр типа a_i элемента C был заменен соответствующим параметром типа T_i. "

4 голосов
/ 24 февраля 2012

Я думаю, что ваш вопрос может быть разбит на три отдельные проблемы:

Что с параметрами нескольких типов для классов / черт / и т.д.

Классическим примером является карта от одного типа объекта к другому. Если вы хотите, чтобы тип ключей отличался от типа значения, но оставляете оба общих значения, вам нужны два параметра типа. Таким образом, карта [A, B] принимает ключи универсального типа A и отображает значения универсального типа B. Пользователь, которому нужна карта из закладок в страницы, объявил бы ее как Map [Bookmark, Page]. Наличие только одного типа параметров не позволило бы это различие.

Из того, что я предполагаю, Foo [T1, T2] просто означает, что он определил два типа параметров, он не должен принимать T1 и возвращать T2.

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

Что это за +/-?

Они ограничивают то, с чем могут связываться параметры типа. Учебник Scala by Example имеет хорошее объяснение. См. Раздел 8.2 Аннотации отклонений.

Что такое функция в scala?

Почему они помещают тип возврата в скобки? Означает ли это все последний параметр в скобках является типом возвращаемого значения? Или они только что произошли определил новый тип R для возвращаемого типа?

В руководстве Scala by Example это хорошо объясняется в разделе 8.6 Функции.

1 голос
/ 18 марта 2011

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

Спецификация Scala дает следующий пример для Trait с несколькими параметрами:

Рассмотрим абстрактный класс Table, который реализует карты от типа ключей A к типу значений B.
У класса есть метод, установленный для ввода новой пары ключ / значение в таблицу, и метод get, который возвращает необязательное значение, соответствующее данному ключу.
Наконец, существует метод apply, аналогичный get, за исключением того, что он возвращает заданное значение по умолчанию, если таблица не определена для данного ключа. Этот класс реализован следующим образом.

abstract class Table[A, B](defaultValue: B) {
  def get(key: A): Option[B]
  def set(key: A, value: B)
  def apply(key: A) = get(key) match {
    case Some(value) => value
    case None => defaultValue
  }
}

Вот конкретная реализация класса Table.

class ListTable[A, B](defaultValue: B) extends Table[A, B](defaultValue) {
  private var elems: List[(A, B)]
  def get(key: A) = elems.find(._1.==(key)).map(._2)
  def set(key: A, value: B) = { elems = (key, value) :: elems }
}

Вот черта, которая предотвращает одновременный доступ к операциям get и set его родительский класс

trait Synchronized Table[A, B] extends Table[A, B] {
  abstract override def get(key: A): B =
  synchronized { super.get(key) }
  abstract override def set((key: A, value: B) =
    synchronized { super.set(key, value) }
}

Обратите внимание, что SynchronizedTable не передает аргумент своему суперклассу, Table, даже если Table определяется формальным параметром.
Также обратите внимание, что супер вызовы в методах get и set SynchronizedTable статически ссылаются на абстрактные методы в классе Table. Это допустимо, если вызывающий метод помечен как абстрактное переопределение (§5.2).

Наконец, следующая композиция mixin создает таблицу синхронизированного списка с строки как ключи и целые числа как значения со значением по умолчанию 0:

object MyTable extends ListTable[String, Int](0) with SynchronizedTable

Объект MyTable наследует свой метод get и set от SynchronizedTable.
Супер вызовы в этих методах связаны с ссылками на соответствующие реализации в ListTable, который является действительным супертипом SynchronizedTable в MyTable.

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