我甚至不确定如何描述我在做什么,除了一个例子:
class Node
abstract class App {
def schema: Node
}
def bind(app: App, f: Node => Node) {
f(app.schema)
}
val app = new App {
val schema = new Node {
val child = new Node
}
}
bind(app, _.child)
这不编译。我从error: value child is not a member of this.Node
电话中获得bind
。
我不知道如何解决这个问题,但我认为它可能涉及使用参数化类型。我需要f
的参数类型为分配给Node
的实际schema
子类的参数。
编辑:我无法明确命名我的Node
子类型,因为在现实生活中我有完整的静态定义Node
树,并且名称不实用它们。
答案 0 :(得分:4)
Ǹode
没有方法child
所以类App必须保留封闭节点的参数:
abstract class App[N <: Node] {
def schema: N
}
然后你可以扩展Node
以包含child:
class ParentNode extends Node {
def child = new ParentNode
}
最后,您可以将bind
写为:
def bind[N <: Node](app: App[N], f: N => N) = {
f(app.schema)
}
val app = new App[ParentNode] {
val schema = new ParentNode
}
答案 1 :(得分:3)
您可以执行以下操作:
def bind[T](app: App{val schema: T}, f: T => Node) { f(app.schema) }
bind[{val child: Node}](app, _.child)
我认为这对你想要达到的目标来说仍然过于冗长。
答案 2 :(得分:2)
bind
已签名App x (Node => Node) => Node
_.child
表示{n: Node => n.child}
,而Node未定义子项。这是您的错误消息告诉的内容。
在您的特定情况下,您可以期望它可以工作,因为您知道bind的函数参数应用于app参数的模式节点。但是,您应该告诉编译器几乎一样多。这将迫使您将一些实施细节更公开。
首先,也许你的函数不会有Node参数,但更精确。你可以拥有一个通用参数:
def bind[N <: Node](app: App, f: N => Node)
但是当你打电话给f(app.schema)
时,你必须确保app.schema具有所需的类型
class App[N <: Node] {def schema: N}
def bind[N <: Node](app: App[N], f: N => Node) = f(app.schema)
最后,你必须使你的应用程序的类型更明确,至少
class NodeOfApp{def child: Node}
val app = new App[NodeOfApp]{...}