案例类的隐式解析和伴随对象

时间:2014-01-14 20:14:43

标签: scala functional-programming implicit

我正在尝试向(我认为是)案例类的伴随对象添加隐式值,但找不到此隐式值。

我正在努力实现以下目标:

package mypackage

object Main {
  def main(args: Array[String]): Unit = {
    val caseClassInstance = MyCaseClass("string")
    val out: DataOutput = ...
    serialize(out, caseClassInstance)
    // the above line makes the compiler complain that there is no
    // Serializer[MyCaseClass] in scope
  }
  def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
    ...
  }
}
object MyCaseClass {
  // implicits aren't found here
  implicit val serializer: Serializer[MyCaseClase] = ...
}

case class MyCaseClass(s: String) {
  // some other methods
}

我在这里明确添加了包,以显示MyCaseClass案例类和对象都应该在范围内。我知道该对象实际上正在构建,因为如果我添加

,我可以编译它
implicit val serializer = MyCaseClass.serializer

main(如果我添加import MyCaseClass.serializer,则)。

我担心MyCaseClass对象实际上不是case类的伴侣,因为如果我在对象上明确定义applyunapply然后尝试调用{在MyCaseClass.apply("string") {1}}中,编译器会出现以下错误:

main

如果不可能采用这种方法,是否有办法在每次必须将范围类带入范围时使用带有case类的类型类而不创建隐式值?

编辑:我正在使用scala 2.10.3。

编辑2:这是充实的例子:

ambiguous reference to overloaded definition,
both method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
and  method apply in object MyCaseClass of type (s: String)mypackage.MyCaseClass
match argument types (String)
val a = InputRecord.apply("string")
                    ^

但这实际上是编译的。我在使用Scoobi的package mypackage import java.io.{DataOutput, DataOutputStream} object Main { def main(args: Array[String]): Unit = { val caseClassInstance = MyCaseClass("string") val out: DataOutput = new DataOutputStream(System.out) serialize(out, caseClassInstance) // the above line makes the compiler complain that there is no // Serializer[MyCaseClass] in scope } def serialize[T : Serializer](out: DataOutput, t: T): Unit = { implicitly[Serializer[T]].write(out, t) } } object MyCaseClass { // implicits aren't found here implicit val serializer: Serializer[MyCaseClass] = new Serializer[MyCaseClass] { override def write(out: DataOutput, t: MyCaseClass): Unit = { out.writeUTF(t.s) } } } case class MyCaseClass(s: String) { // some other methods } trait Serializer[T] { def write(out: DataOutput, t: T): Unit } 而不是WireFormat[T]时遇到此问题,但由于复杂性和Scoobi依赖性,无法提供简洁,可运行的示例。我将尝试创建一个更相关的示例,但似乎问题不像我想的那么普遍。

2 个答案:

答案 0 :(得分:1)

事实证明,类型类实例实际上需要是隐式,而不是对象。上面的MyCaseClass对象有效,因为它的序列化程序被赋值为隐式值。但是,实现

object MyCaseClass {
  implicit object MyCaseClassSerializer extends Serializer[MyCaseClass] {
    override def write(out: DataOutput, t: MyCaseClass): Unit = {
      out.writeUTF(t.s)
    }
  }
}

失败并显示错误

Main.scala:9: error: could not find implicit value for evidence parameter of type mypackage.Serializer[mypackage.MyCaseClass]
    serialize(out, caseClassInstance)
             ^ 

在我的真实代码中,我使用辅助函数来生成Serializer[T](请参阅https://github.com/NICTA/scoobi/blob/24f48008b193f4e87b9ec04d5c8736ce0725d006/src/main/scala/com/nicta/scoobi/core/WireFormat.scala#L137)。尽管函数具有自己的显式返回类型,但编译器未正确推断分配值的类型。

以下是使用此类Serializer - 生成器的问题的完整示例。

package mypackage

import java.io.{DataOutput, DataOutputStream}

object Main {
  import Serializer._
  def main(args: Array[String]): Unit = {
    val caseClassInstance = MyCaseClass("string")
    val out: DataOutput = new DataOutputStream(System.out)
    serialize(out, caseClassInstance)
  }
  def serialize[T : Serializer](out: DataOutput, t: T): Unit = {
    implicitly[Serializer[T]].write(out, t)
  }
}

object MyCaseClass {
  import Serializer._
  // does not compile without Serializer[MyCaseClass] type annotation
  implicit val serializer: Serializer[MyCaseClass] = 
      mkCaseSerializer(MyCaseClass.apply _, MyCaseClass.unapply _)
}

case class MyCaseClass(s: String)

trait Serializer[T] {
  def write(out: DataOutput, t: T): Unit
}

object Serializer {
  // does not compile without Serializer[String] type annotation
  implicit val stringSerializer: Serializer[String] = new Serializer[String] {
    override def write(out: DataOutput, s: String): Unit = {
      out.writeUTF(s)
    }
  }

  class CaseClassSerializer[T, A : Serializer](
      apply: A => T, unapply: T => Option[A]) extends Serializer[T] {
    override def write(out: DataOutput, t: T): Unit = {
      implicitly[Serializer[A]].write(out, unapply(t).get)
    }
  }

  def mkCaseSerializer[T, A : Serializer]
      (apply: A => T, unapply: T => Option[A]): Serializer[T] =
    new CaseClassSerializer(apply, unapply)
}

答案 1 :(得分:0)

下面这个相关简单的代码打印1。

object A{
  implicit def A2Int(a:A)=a.i1
}
case class A(i1:Int,i2:Int)

object Run extends App{
  val a=A(1,2)
  val i:Int=a
  println(i)
}