#scala #constructor #implicits
#scala #конструктор #подразумевается
Вопрос:
Я хотел бы добавить неявный параметр в класс с частным конструктором. Здесь в качестве упрощенного примера:
class A[T] private(a:Int){
def this()=this(0)
}
Если я хотел бы применить шаблон Pimp моей библиотеки к T с помощью Ordered [T], мне нужно было бы использовать (устаревший) привязанный вид следующим образом:
class A[T <% Ordered[T]] private(a:Int){
def this()=this(0)
}
И это работает. Однако, чтобы избежать устаревшего синтаксического сахара, я хотел бы передать неявный параметр классу. К сожалению, именно здесь я, вероятно, делаю что-то не так:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()=this(0)
}
Для приведенного выше кода компилятор генерирует следующую ошибку:
error: No implicit view available from T => Ordered[T].
def this()=this(0)
В то время как, если я попытаюсь передать неявный параметр напрямую, вот так:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()=this(0)(conv)
}
Я понимаю это:
error: not found: value conv
def this()=this(0)(conv)
Как передать неявный параметр в этом случае?
РЕДАКТИРОВАТЬ: После еще нескольких экспериментов кажется, что переопределение конструктора с неявным параметром является проблемой. Не факт, что конструктор является закрытым.
Ответ №1:
Я нашел ответ, кажется, что мне нужно явно определить неявный параметр для конструктора без параметров, например:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()(implicit conv:T=>Ordered[T])=this(0)
}
Я прошу прощения за рассылку спама, поэтому в любом случае я приму любой ответ, который содержит более подробное объяснение.
Комментарии:
1. Вам не нужно извиняться, ответы на ваши собственные вопросы вполне приемлемы.
2. @Krle В моей книге довольно сильно пахнет кодом. Для начала было бы неплохо правильно сделать отступ в коде для одного, но я бы этого не стал делать. Вместо этого я бы переместил этот перегруженный конструктор в сопутствующий метод apply с тем же неявным, который выглядит немного чище.
3. @flavian Спасибо, я сделаю это. Не могли бы вы пояснить, почему? Как для отступа, так и для сопутствующего объекта…
Ответ №2:
Scala обеспечивает упорядочение в 2 вариантах: один через наследование с Ordered
, а другой, который на самом деле намного более уместен здесь, — через контекстные границы с использованием Ordering
класса типов.
Ваш подход на самом деле не является идиоматическим, и если бы у вас было что-то, что фактически использовало предоставленное вами неявное, вы бы получили неоднозначное неявное исключение во время компиляции, потому что и конструктор, и метод определяют одно и то же неявное.
Что я бы сделал, так это:
class A[T : Ordering] private(a: Int)
На самом деле это сокращенный синтаксис для:
class A[T] private(a: Int)(implicit ev: Ordering[T])
Затем вы можете использовать этот аргумент либо явно, либо implicitly
.
Если вы определяете его с помощью сокращенного T : Ordering
синтаксиса.
class A[T : Ordering] private(a: Int) {
def revSorter(list: List[T]): List[T] = {
list.sorted(implicitly[Ordering[T]].reverse)
}
}
Если вы определяете его с помощью «явного» синтаксиса:
class A[T] private(a: Int)(implicit ev: Ordering[T]) {
def revSorter(list: List[T]): List[T] = {
list.sorted(ev.reverse)
}
}
Комментарии:
1. Да, я согласен с ограничениями контекста, но я предполагаю, что основной смысл был в том, как переопределить конструктор с неявными параметрами. Я должен был использовать общий класс B в примере, а не упорядочивать [T].