没有类型的隐式参数:任何

No Implicit arguments of Type: Any

我关注了这篇文章create union types。这些文章对原始类型的回答很少,但我的场景是对其的扩展。

所以,我正在尝试定义一个采用 Map[String, A] 的方法,其中 A 是允许类型的集合。

这是我的 class 联合类型:

sealed trait SupportedType[A]

object SupportedType {
  implicit val byteBufferColumn : SupportedType[ByteBuffer] = new SupportedType[ByteBuffer] {}
  implicit val longColumn : SupportedType[java.lang.Long] = new SupportedType[java.lang.Long] {}
  implicit val byteArrayColumn : SupportedType[Array[Byte]] = new SupportedType[Array[Byte]] {}
  implicit val stringColumn : SupportedType[String] = new SupportedType[String] {}
}

这是我定义的方法:

def upsert[A: SupportedType](key: T, values: Map[String, A], timestamp: Long, ttl: Duration): Future[Unit]

我是这样调用方法的:

dataStore.upsert(
      cacheKey,
      Map(
        itColumn      -> ByteBuffer.wrap(Utils.compress(iti.toByteArray)),
        cacheWriteTimeColumn -> writeTime.toEpochMilli
      ),
      writeTime.toEpochMilli,
      ttl
    )

错误:No implicit arguments of type: SupportedType[Any]

我的猜测是 writeTime.toEpochMilli returns java.long 类型,正如您在 SupportedType 中看到的那样,我尝试定义 java.lang.Long 但那是行不通的。

如有任何帮助,我们将不胜感激。

您可以将 magnet 模式与 typeclass 组合使用,如下所示:

import scala.language.implicitConversions

trait ColumnValue {
  def serialize(): String
}

object ColumnValue {
  trait SupportedType[A] {
    def toColumn(a: A): ColumnValue
  }
  
  object SupportedType {
    implicit final val stringSupportedType: SupportedType[String] =
      new SupportedType[String] {
        override def toColumn(str: String): ColumnValue =
          new ColumnValue {
            override def serialize(): String =
              "\"" + str + "\""
          }
      }
    
    implicit final val intSupportedType: SupportedType[Int] =
      new SupportedType[Int] {
        override def toColumn(int: Int): ColumnValue =
          new ColumnValue {
            override def serialize(): String =
              int.toString
          }
      }
    
    implicit final val booleanSupportedType: SupportedType[Boolean] =
      new SupportedType[Boolean] {
        override def toColumn(bool: Boolean): ColumnValue =
          new ColumnValue {
            override def serialize(): String =
              if (bool) "1" else "0"
          }
      }
    
    implicit final def listSupportedType[A](implicit ev: SupportedType[A]): SupportedType[List[A]] =
      new SupportedType[List[A]] {
        override def toColumn(list: List[A]): ColumnValue =
          new ColumnValue {
            override def serialize(): String =
              list.map(a => ev.toColumn(a).serialize()).mkString("[", ",", "]")
          }
      }
  }
  
  def apply[A](a: A)(implicit ev: SupportedType[A]): ColumnValue =
    ev.toColumn(a)
  
  implicit def supportedType2Column[A : SupportedType](a: A): ColumnValue =
    apply(a)
}

You may create some helper functions to reduce some of the boilerplate.

可以这样使用:

final case class Table(data: Map[String, ColumnValue]) {
  def upsert(values: Map[String, ColumnValue]): Table =
    copy(this.data ++ values)
}

object Table {
  val empty: Table =
    Table(data = Map.empty)
}

val result = Table.empty.upsert(Map(
  "a" -> "foo",
  "b" -> 10,
  "c" -> List(true, false, true)
))

见代码运行here.