Scala Can';我不觉得含蓄,我也不';我不知道为什么——有人能给我指出正确的方向吗?
我正在尝试编写一个工厂来创建案例类。我正在创建一个命令行工具,它接受case类参数的字符串表示。无论如何,我的想法是限制对新类型创建隐式的添加的更改,但我似乎无法越过起点。下面是一些试图创建case对象的代码(因此没有参数,这是最简单的情况),但scalac抱怨它“找不到参数工厂的隐式值”。一定是个笨蛋,但我已经想尽一切办法了。如果有人能给我指出正确的方向,我将不胜感激。谢谢Scala Can';我不觉得含蓄,我也不';我不知道为什么——有人能给我指出正确的方向吗?,scala,scala-implicits,Scala,Scala Implicits,我正在尝试编写一个工厂来创建案例类。我正在创建一个命令行工具,它接受case类参数的字符串表示。无论如何,我的想法是限制对新类型创建隐式的添加的更改,但我似乎无法越过起点。下面是一些试图创建case对象的代码(因此没有参数,这是最简单的情况),但scalac抱怨它“找不到参数工厂的隐式值”。一定是个笨蛋,但我已经想尽一切办法了。如果有人能给我指出正确的方向,我将不胜感激。谢谢 object Message { case object Person seale
object Message {
case object Person
sealed trait Repr[T] {
def value: T
}
trait Parm0Factory[R] {
def instance(): R
}
implicit val personFactory = new Parm0Factory[Person.type] {
def instance() = Person
}
case class Parm0[R]() extends Repr[R] {
override def value(): R = xform
private def xform(implicit factory: Parm0Factory[R]): R = factory.instance()
}
def main(args: Array[String]): Unit = {
val t1 = Parm0[Person.type]()
println(t1.value)
}
}
您对
PersonFactory[Person.Type]
有一个隐式定义,但是您的xform
调用正在查找而没有找到的是PersonFactory[R]
。它不是同一种类型。我做了一些研究,并能够实现我的想法,目前这是相当令人满意的(至少对我来说)。简单地说,我想维护递归树结构的字符串表示形式,用户可以就地修改它,然后将该表示形式转换为实际实例。事实证明类型类正是我想要的。我想我会继续为那些至少和我一样不熟悉使用类型类的人发布这篇文章。
如果有人知道如何消除必须为“build”调用提供类型参数的必要性,请告诉我。此外,我希望隐式构建器函数的实现更清晰,不使用“@unchecked”注释来消除恼人的编译器警告。:-)
您应该在包含
xform
callNah的上下文中导入您的personFactory
以及Person
,因为它已经在范围内。问题是它不是正确的类型。是的。但我遗漏了一些重要的东西。呼叫站点。(见下文)。显然R不是Person.type,但是泛型在其他情况下是无用的(??)。它是否应该根据呼叫信息解析为Person.type?可能仅仅声明类型是不够的-它需要具有该类型的参数?defmain(args:Array[String]):Unit={val t1=Parm0[Person.type]()println(t1.value)}泛型在这种情况下确实是无用的,是的。它无法根据调用信息“解析为”Person.type,因为“调用信息”将其解析为R
。如果您声明value()
返回Person.type
,则它将工作,除非它不符合Repr[R]
definition。现在,如果您将R
对象一起删除,并将其声明为class Parm0 extends Repr[Person.type]
,可以编译。这有意义吗?是的。但我无法完成我在这种情况下试图做的事情。也就是说,创建一个“类的类”作为案例类的工厂-一个“类”用于不同数量的参数。所以我想很明显,我的做法是错误的。:-)显然拥有一个工厂
就是让它针对不同的情况做一些不同的事情。如果你只定义了一个,你也可以明确地说出来。嗯,是的。“工厂”部分将是R部分-要生产的实例的类型。你对如何实现这一点有什么建议吗?
object Messages {
// Test classes
case class Person(name: String, age: Int, pet: Dog)
case class Dog(name: String)
case class Device(deviceType: DeviceType, on: Boolean)
sealed trait DeviceType
case class Android() extends DeviceType
case class iOS() extends DeviceType
case class Windows() extends DeviceType
// Builders...
trait Builder[A] {
def build: Node => A
}
object Builder {
def build[A](f: Node => A) = new Builder[A] {
val build = f
}
// Terminals...
implicit val intBuilder: Builder[Int] = build(node => (node: @unchecked) match {
case Term(_, value) => value.toInt
})
implicit val stringBuilder: Builder[String] = build(node => (node: @unchecked) match {
case Term(_, value) => value
})
implicit val booleanBuilder: Builder[Boolean] = build(node => (node: @unchecked) match {
case Term(_, value) => value.toBoolean
})
// Case classes (composites)
implicit val dogBuilder: Builder[Dog] = build[Dog](node => (node: @unchecked) match {
case Tree(_, children) =>
Dog(children(0).build[String])
})
implicit val personBuilder: Builder[Person] = build[Person](node => (node: @unchecked) match {
case Tree(_, children) =>
Person(children(0).build[String], children(1).build[Int], children(2).build[Dog])
})
implicit val deviceTypeBuilder: Builder[DeviceType] = build[DeviceType](node => (node: @unchecked) match {
case Term(_, value) => value match {
case "Android" => Android()
case "iOS" => iOS()
case "Windows" => Windows()
}
})
implicit val deviceBuilder: Builder[Device] = build[Device] (node => (node: @unchecked) match {
case Tree(_, children) => Device(children(0).build[DeviceType], children(1).build[Boolean])
})
}
// Data Structures...
sealed trait Node {
val name: String
def prompt: String
def build[A: Builder]: A = implicitly[Builder[A]].build(this)
}
case class Tree(name: String, children: IndexedSeq[Node]) extends Node {
override def prompt = {
val choices = children.zipWithIndex.map { case (node, idx) => s"${idx + 1}) ${node.name}" }.mkString("\n")
s"$toString\n$choices\n"
}
override def toString = name + children.mkString("(", ", ", ")")
}
case class Term(name: String, value: String) extends Node {
override def prompt = s"$name = "
override def toString = s"$name = $value"
}
def main(args: Array[String]): Unit = {
val person = Tree("Person", IndexedSeq[Node](Term("name", "Fred"), Term("age", "45"),
Tree("pet", IndexedSeq[Node](Term("name", "Fido")))))
val device = Tree("some device", IndexedSeq[Node](Term("type", "iOS"), Term("on", "true")))
println(person.prompt)
println(person.toString)
// TODO How to remove necessity of providing type parameter?
println(person.build[Person])
println(device.build[Device])
}
}