【问题标题】:No Implicit arguments of Type: Any没有类型的隐式参数:任何
【发布时间】:2021-08-09 19:25:54
【问题描述】:

我关注这篇文章到create union types。这些文章几乎没有关于 Primitive 类型的答案,但我的场景是它的扩展。

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

这是我的联合类型类:

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 返回 java.long 类型,正如您在 SupportedType 中看到的,我尝试定义 java.lang.Long 但那不起作用。

任何帮助将不胜感激。

【问题讨论】:

  • Map 并不知道其中的所有元素都有一个正确的 typeclass 实例。您的选择是,使用 magnet 模式,或者将每个值与另一个类中的 typeclass 实例一起压缩。
  • 你能举个例子吗?
  • 请问,稍后您将如何处理 Map 中的这些值?也许你想要做的就是调用像serialize 这样的单个方法,它将值转换为字节缓冲区或类似的东西?
  • 这张地图包含将存储在数据库中的列名、列值,是的,我想到了与您所说的相同的事情,但是使用团队中当前的设计方法,我存储了每个分别列
  • this 之类的内容是否适用于您的用例?如果是这样,请告诉我将其发布为答案。

标签: scala generics type-conversion


【解决方案1】:

您可以将 ma​​gnet 模式与 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)
}

您可以创建一些辅助函数来减少一些样板。

可以这样使用:

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

【讨论】:

    猜你喜欢
    • 2018-05-30
    • 2021-06-09
    • 2021-07-20
    • 2020-02-20
    • 1970-01-01
    • 2021-10-28
    • 2023-03-08
    • 2020-02-02
    • 2022-01-07
    相关资源
    最近更新 更多