gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 01:29:42 26 4
gpt4 key购买 nike

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

我正在尝试实现以下目标:

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 object 实际上不是 case 类的伴侣,因为如果我明确定义 applyunapply在对象上,然后尝试调用 MyCaseClass.apply("string")main ,编译器给出以下错误:
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")
^

如果不可能采用这种方法,是否有一种方法可以将类型类与 case 类一起使用,而不必在每次必须将其引入作用域时创建隐式值?

编辑:我使用的是 Scala 2.10.3。

编辑 2:这是充实的示例:
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
}

不过,这实际上可以编译。我在使用 Scoobi 的 WireFormat[T] 时遇到了这个问题而不是 Serializer ,但由于复杂性和 Scoobi 依赖性,无法提供简洁、可运行的示例。我将尝试创建一个更相关的示例,但问题似乎并不像我想象的那么普遍。

最佳答案

事实证明,类型类实例实际上需要是隐式值,而不是对象。 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)
}

关于scala - 案例类的隐式解析和伴随对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21123087/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com