Scala: сложный случай, включающий анонимные подклассы, обратные вызовы и параметры типа - PullRequest
4 голосов
/ 02 августа 2011

Я даже не уверен, как описать, что я делаю, кроме как с примером:

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 с, и было бы нецелесообразно называть их.

Ответы [ 3 ]

4 голосов
/ 03 августа 2011

Ǹode не имеет метода child, поэтому класс App должен сохранять параметр вложенного узла:

abstract class App[N <: Node] {
  def schema: N
}

Затем вы можете расширить Node, включив в него дочерний элемент:

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
 }
3 голосов
/ 03 августа 2011

Вы можете сделать что-то вроде:

def bind[T](app: App{val schema: T}, f: T => Node) { f(app.schema) }
bind[{val child: Node}](app, _.child)

Я думаю, что это все еще слишком многословно для того, чего вы пытаетесь достичь.

2 голосов
/ 03 августа 2011

bind имеет подпись App x (Node => Node) => Node

_.child в этом контексте означает {n: Node => n.child}, а Node не определяет дочерний элемент. Вот что говорит ваше сообщение об ошибке.

В вашем конкретном случае вы можете ожидать, что он будет работать, потому что вы знаете, что аргумент функции bind применяется к узлу схемы аргумента приложения. Тем не менее, вы должны сказать почти столько же компилятору. И это заставит вас сделать некоторые детали реализации более публичными.

Во-первых, возможно, ваша функция не будет иметь аргумента 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)

Последнее, вам нужно будет сделать тип вашего приложения val более явным, по крайней мере,

class NodeOfApp{def child: Node}
val app = new App[NodeOfApp]{...}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...