Класс Scala с частным конструктором и неявным параметром

#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].