Как внести в объект, предшествующий другому объекту? - PullRequest
2 голосов
/ 23 июня 2019

С учетом следующего случая:

  trait Companion {

    implicit def str(a: A): String =
      s"${this.getClass.getSimpleName}: %d" format a.n
  }

  class A(val n: Int)
  object A extends Companion {}

  class B(val x: Int, y: Int) extends A(y)
  object B extends Companion {}

Теперь компиляция следующего кода вызовет расходящуюся неявную ошибку:

val b = new B(5, 2)
val s: String = b
println(s)

, поскольку оба объекта A и AA находятся в неявной области действия по умолчаниюАА.Это явно дефектно: класс AA более «точен», чем черта A, поэтому его неявная область действия должна иметь более высокий приоритет.К сожалению, поскольку объекты не могут наследоваться друг от друга, это невозможно объявить.

Поэтому мой вопрос: каков наилучший способ достичь этого, не прибегая к неявной области действия по умолчанию?

Ответы [ 2 ]

1 голос
/ 23 июня 2019

Теперь компиляция следующего кода вызовет расходящуюся неявную ошибку:

Это не «расходящаяся неявная ошибка», это неоднозначность, неявная неоднозначность и неявная дивергенция различны.

Последствия относительно типа X должны идти на объект-компаньон X. Так что, если это неявное преобразование между A и String, оно должно перейти к объекту-компаньону A. Но тогда у вас есть проблема с .getSimpleName.

Общий подход - параметризация родительской черты для сопутствующих объектов (как @MarioGalic советует ):

https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/generic/GenericCompanion.scala#L30

https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/typeclass.scala#L44

# L84 # L150 # L178

Если вы не хотите делать T параметром типа, вы можете сделать его членом типа

trait Companion {    
  type T <: A
  implicit def str(a: T): String = s"${this.getClass.getSimpleName}: %d" format a.n
}

class A(val n: Int)
object A extends Companion { 
  type T = A 
}

class B(val x: Int, y: Int) extends A(y)
object B extends Companion { 
  type T = B 
}

Также вы можете попробовать переопределить неявное

trait Companion {
  implicit def str(a: A): String = s"${this.getClass.getSimpleName}: %d" format a.n
}

class A(val n: Int)
object A extends Companion 

class B(val x: Int, y: Int) extends A(y)
object B extends Companion {
  override implicit def str(a: A): String = super.str(a)
}

или

trait LowPriorityCompanion {
  implicit def str(a: A): String = s"${this.getClass.getSimpleName}: %d" format a.n
}

trait Companion extends LowPriorityCompanion {
  override implicit def str(a: A): String = super.str(a)
}

class A(val n: Int)
object A extends LowPriorityCompanion 

class B(val x: Int, y: Int) extends A(y)
object B extends Companion 
0 голосов
/ 23 июня 2019

Попробуйте параметризовать Companion черту так:

  trait Companion[T <: A] {

    implicit def str(a: T): String =
      s"${this.getClass.getSimpleName}: %d" format a.n
  }

  class A(val n: Int)
  object A extends Companion[A] {}

  class B(val x: Int, y: Int) extends A(y)
  object B extends Companion[B] {}

  val b = new B(5, 2)
  val s: String = b
  println(s) // B$: 2
...