Это очень просто. Ваш первый пример относится к концепции generics.
Дженерик имеет простую цель, чтобы сделать определенные методы родового, например, не зависят от типа.
Давайте рассмотрим этот тривиальный пример. Скажем, я хочу написать метод drop1
для List
.
Я могу либо написать один для каждого типа: (медленно, повторяющийся):
def drop1(l: List[Int]): List[Int] = l.tail // this only works for Int
def drop1(l: List[String]): List[String] = l.tail // this only works for String
Вы можете увидеть, как вы должны были бы написать выше для каждого отдельного типа. Чтобы преодолеть это, у вас есть дженерики:
def drop1[A](l: List[A]): List[A] = l.tail // this works for any given type.
, который по существу говорит: Вне зависимости от типа, содержащиеся в списке, дают мне хвост. Вместо того, чтобы писать тысячи вариантов drop1
для практически бесконечного числа типов, мне нужно только написать один.
Сейчас в Scala, ваша реализация лучше всего сделать с:
implicit class ListOps[A](val l: List[A]) extends AnyVal {
def drop1: List[A] = l match {
case head :: tail => tail
case Nil => Nil
}
}
// you can now have
List(1, 2, 3).drop1
Это также вообще плохая идея переименовать хорошо известные методы библиотеки. Операция tail
небезопасна, а drop
безопасен. Все, что вы вызываете, - путаница, поскольку существует метод по умолчанию drop
.
List(1, 2, 3) drop 1
Спасибо за ваш ответ. Почему именно первый '[A]' нужен в моем первом примере? Это просто требование синтаксиса? – Caballero
Да, поэтому компилятор может различать тип, который вы вводите из некоторого уже определенного типа A. Почему? Чтобы вы не ошиблись и не делаете свое намерение явным. –
Спасибо. По сути, во время чтения этого урока я поднял этот вопрос. – Caballero