2012-02-10 10 views
7

Sto cercando di capire come creare un metodo che accetta un oggetto nidificato come argomento. Per una classe annidata posso effettuare le seguenti operazioni:Qual è il tipo di oggetto nidificato in scala

scala> class Outer { 
| class Inner 
| def method(i:Outer#Inner) = { "inner class" } 
| } 
defined class Outer 

Tuttavia, se cerco qualcosa di simile a un oggetto invece ottengo un errore:

scala> class Outer { 
| object Inner 
| def method(i:Outer#Inner) = { "inner object" } 
| } 
<console>:11: error: type Inner is not a member of Outer 
    def method(i:Outer#Inner) = { "inner object" } 

cosa dovrebbe il tipo di argomento al il metodo è per realizzare questo? Voglio anche fare riferimento al tipo di oggetto Inner non generalizzare l'argomento per dire Any.

risposta

12

Inner è un oggetto, quindi non è un tipo e non può essere utilizzato come tipo. il tipo di Inner è Inner.type. Significa, nel tuo esempio. Sfortunatamente, ogni istanza di Outer avrà il proprio oggetto interno e il tipo Outer#Inner.type non può essere utilizzato, poiché non è stabile. Una soluzione alternativa è: this.Inner.type.

def method(i:this.Inner.type) = { "inner object" } 

ma significa che si può passare solo come parametro l'oggetto interno dell'istanza su cui si chiama method.

+0

Questo non può essere compilato. –

+1

Oups, lo userete anche al posto di Outer. Devo leggere di nuovo la spiegazione sul tipo dipendente per spiegarlo. – Nicolas

+0

Sì, questo funziona! Anche per usare Inner in un metodo definito al di fuori della classe Outer posso definire in Outer: 'type InnerType = this.Inner.type' E quindi posso definire un metodo come:' def metodo (i: Outer # InnerType) = "foo" ' –

7

Un semplice esempio per illustrare ciò che sta succedendo qui (nella REPL):

object A 
def foo(a : A) = "Does not compile" 
def bar(a : A.type) = "Does compile!" 
bar(A) // returns "Does compile!" 

Come dice Nicola, interno non è un tipo, quindi non è possibile usarlo come tale.

Cercando di capire la tua motivazione, mi si avvicinò con qualcosa di simile:

class Outer(i : Int) { 
    object Inner { 
    def getI : Int = i 
    } 
    def foo(x : Inner.type) = x.getI 
} 

Questo è un po 'inutile, dal momento che ci sarebbe solo fare riferimento direttamente interna - dopo tutto, c'è solo una di essa:

class Outer(i : Int) { 
    object Inner { 
    def getI : Int = i 
    } 
    def foo = Inner.getI 
} 

Immagino che quello che vuoi fare sia accettare un Inner da qualsiasi istanza di Outer. Siamo in grado di controllare il tipo di una cosa del genere:

val o = new Outer(1) 
:type o.Inner 
o.Inner.type 

Così ci si potrebbe aspettare di essere in grado di fare qualcosa del genere:

class Outer(i : Int) { 
    object Inner { 
    def getI : Int = i 
    } 
    def foo(x : Outer#Inner.type) = x.getI 
} 

Questo, tuttavia, non riesce a compilare. Non sono sicuro del perché. Digita alias per il salvataggio!

class Outer(i : Int) { 
    type Inner = Inner.type 
    object Inner { 
    def getI : Int = i 
    } 
    def foo(x : Outer#Inner) = x.getI 
} 

val a = new Outer(1) 
val b = new Outer(2) 
a.foo(b.Inner) //returns 2 

sto indovinando è solo una limitazione del parser che è in grado di leggere qualcosa della forma A#B.type. Potresti potenzialmente inviare una richiesta di bug.

+0

Il 'type Inner = Inner.type' è uguale a' type Inner = this.Inner.type'? o quei due si riferiscono a due diversi tipi? –

+1

Sì, si riferiscono alla stessa cosa. – Submonoid

0

Ogni Scala object ha un proprio tipo e c'è esattamente un valore di quel tipo - l'oggetto stesso. Pertanto, il tipo di Scala object non è più utile del tipo Unit.

Per esempio, supponiamo di avere un object A e dichiarare un metodo o una funzione che prende un parametro A.type:

def foo(arg: A.type) = {} 

Dal momento che ci sarà sempre esistere esattamente un valore di tipo A.type, perdiamo nessuna generalità da invece riferimento direttamente nel metodo foo.

Se vi trovate a voler fare questo, è più probabile che ciò che si vuole veramente astratto su è un tratto o base classe dell'oggetto:

trait Useful { def usefulness: Int } 
object A extends Useful { override val usefulness = 42 } 
class Foo { 
    def foo(arg: Useful) = arg.usefulness 
} 
Problemi correlati