【问题标题】:Scala diverging implicit expansionScala 发散隐式扩展
【发布时间】:2019-03-15 08:51:20
【问题描述】:

我想为通用 enumeratum.values.ValueEnumEntry[ValueType] 编写一个 anorm.ToStatement 实例。但似乎没有正确推断出 ValueType。

我的代码:

import java.sql.PreparedStatement
import anorm._
import enumeratum.values._

sealed trait Test extends IntEnumEntry
object Test extends IntEnum[Test] {
  case object One extends Test {val value = 1}
  val values = findValues
}

implicit def valueEnumEntryToStatement[ValueType: ToStatement, A <: ValueEnumEntry[ValueType]]: ToStatement[A] =
  (s: PreparedStatement, index: Int, v: A) => implicitly[ToStatement[ValueType]].set(s, index, v.value)

val toStatement: ToStatement[Test] = implicitly[ToStatement[Test]] //NOT OK: diverging implicit expansion for type anorm.ToStatement[ValueType]

类型 anorm.ToStatement[ValueType] 的发散隐式扩展失败。

但如果我明确设置 Int 类型,它会起作用。

//either
implicit def valueEnumEntryToStatement[A <: ValueEnumEntry[Int]]: ToStatement[A] =
  (s: PreparedStatement, index: Int, v: A) => implicitly[ToStatement[Int]].set(s, index, v.value)

val toStatement: ToStatement[Test] = implicitly[ToStatement[Test]] //OK
//or
def valueEnumEntryToStatement[ValueType: ToStatement, A <: ValueEnumEntry[ValueType]]: ToStatement[A] =
  (s: PreparedStatement, index: Int, v: A) => implicitly[ToStatement[ValueType]].set(s, index, v.value)
implicit def intEnumEntryToStatement[A <: IntEnumEntry]: ToStatement[A] = valueEnumEntryToStatement[Int, A]

val toStatement: ToStatement[Test] = implicitly[ToStatement[Test]]

有没有办法在不显式设置类型的情况下制定通用解决方案?

【问题讨论】:

    标签: scala anorm


    【解决方案1】:

    问题在于ValueType 是 trait ValueEnumEntry 中的类型参数,并且那里没有类型成员 ValueType(所以我们不能使用类型 Test#ValueType)。尝试定义一个类型类

      import java.sql.PreparedStatement
      import anorm._
      import enumeratum.values._
    
      sealed trait Test extends IntEnumEntry
      object Test extends IntEnum[Test] {
        case object One extends Test {val value = 1}
        val values = findValues
      }
    
      trait ValueEnumValueType[EntryType <: ValueEnumEntry[_]] {
        type ValueType
      }
      object ValueEnumValueType {
        type Aux[EntryType <: ValueEnumEntry[_], VT] = ValueEnumValueType[EntryType] { type ValueType = VT }
        implicit def byte[A <: ByteEnumEntry]    : Aux[A, Byte]   = null
        implicit def char[A <: CharEnumEntry]    : Aux[A, Char]   = null
        implicit def int[A <: IntEnumEntry]      : Aux[A, Int]    = null
        implicit def long[A <: LongEnumEntry]    : Aux[A, Long]   = null
        implicit def short[A <: ShortEnumEntry]  : Aux[A, Short]  = null
        implicit def string[A <: StringEnumEntry]: Aux[A, String] = null
      }
    
      implicit def valueEnumEntryToStatement[ValueType, A <: ValueEnumEntry[ValueType]](implicit
        enumValueType: ValueEnumValueType.Aux[A, ValueType],
        toStatement: ToStatement[ValueType]): ToStatement[A] =
        (s: PreparedStatement, index: Int, v: A) => toStatement.set(s, index, v.value)
    
      val toStatement: ToStatement[Test] = implicitly[ToStatement[Test]]
    

    【讨论】:

      猜你喜欢
      • 2017-12-30
      • 1970-01-01
      • 1970-01-01
      • 2021-09-23
      • 2012-03-18
      • 1970-01-01
      • 2015-03-30
      • 1970-01-01
      • 2014-01-01
      相关资源
      最近更新 更多