4 Stimmen

Scala: ein kniffliger Fall mit anonymen Unterklassen, Rückrufe und Typ-Parameter

Ich bin mir nicht einmal sicher, wie ich beschreiben soll, was ich tue, außer mit einem Beispiel:

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)

Dies lässt sich nicht kompilieren. Ich erhalte: error: value child is not a member of this.Node von der bind anrufen.

Ich bin nicht sicher, wie man das beheben kann, aber ich denke, dass es wahrscheinlich die Verwendung von parametrisierten Typen beinhaltet. Ich brauche den Typ von f der Parameter des aktuellen Node Unterklasse zugewiesen schema .

EDIT: Ich kann meinen Namen nicht explizit nennen Node Untertypen, denn im wirklichen Leben habe ich ganze Bäume von statisch definierten Node s und es wäre nicht sinnvoll, sie zu benennen.

4voto

paradigmatic Punkte 39621

Node hat keine Methode child so muss die Klasse App den Parameter des eingeschlossenen Knotens beibehalten:

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

Dann können Sie die Node Kind einschließen:

class ParentNode extends Node {
  def child = new ParentNode
}

Schließlich können Sie schreiben bind als:

 def bind[N <: Node](app: App[N], f: N => N) = {
    f(app.schema)
 }

 val app = new App[ParentNode] {
    val schema = new ParentNode
 }

3voto

Dave Rostron Punkte 31

Sie könnten etwas wie folgt tun:

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

Ich vermute, das ist immer noch zu langatmig für das, was Sie erreichen wollen.

2voto

Didier Dupont Punkte 29128

bind hat Unterschrift App x (Node => Node) => Node

_.child bedeutet in diesem Zusammenhang {n: Node => n.child} und Node definiert kein Kind. Das ist, was Ihre Fehlermeldung sagt.

In Ihrem speziellen Fall könnten Sie erwarten, dass es funktioniert, weil Sie wissen, dass das Funktionsargument von bind auf den Schemaknoten des App-Arguments angewendet wird. Allerdings sollten Sie dem Compiler fast genauso viel mitteilen. Und das wird Sie dazu zwingen, einige der Implementierungsdetails zu veröffentlichen.

Erstens, vielleicht wird Ihre Funktion nicht ein Node-Argument haben, sondern etwas genaueres. Sie könnten das hat einen generischen Parameter haben:

def bind[N <: Node](app: App, f: N => Node)

Aber wenn Sie dann anrufen f(app.schema) dann müssen Sie sicherstellen, dass app.schema den erforderlichen Typ hat

class App[N <: Node] {def schema: N}
def bind[N <: Node](app: App[N], f: N => Node) = f(app.schema)

Als Letztes müssen Sie den Typ Ihrer Anwendung val deutlicher machen, zumindest

class NodeOfApp{def child: Node}
val app = new App[NodeOfApp]{...}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X