2012-02-10 17 views
7

? Estoy intentando descubrir cómo crear un método que tome un objeto anidado como argumento. Para una clase anidada que pueda hacer lo siguiente:¿Cuál es el tipo de objeto anidado en scala

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

Sin embargo, si intento algo así con un objeto en lugar consigo un error:

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" } 

¿Qué debe el tipo de argumento a la método para lograr esto? También quiero referirme al tipo de objeto Inner no generalizar el argumento para decir Any.

Respuesta

12

Inner es un objeto, por lo tanto, no es un tipo, y no se puede utilizar como un tipo. el tipo de Inner es Inner.type. Significa, en tu ejemplo. Desafortunadamente, cada instancia de Outer tendrá su propio objeto interno y no se puede usar el tipo Outer#Inner.type, ya que no es estable. Una solución alternativa es usar: this.Inner.type.

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

sino que significa que sólo se puede pasar como parámetro el objeto interno de la instancia en la que se llama a method.

+0

Esto no compila. –

+1

Oups, también deberías usar esto, en lugar de Outer. Debo volver a leer la explicación sobre el tipo dependiente para explicarlo. – Nicolas

+0

Sí, esto funciona! También para usar Inner en un método definido fuera de la clase Outer, puedo definir en Outer: 'type InnerType = this.Inner.type' Y luego puedo definir un método como:' def method (i: Outer # InnerType) = "foo" ' –

7

Un ejemplo sencillo para ilustrar lo que está pasando aquí (en el REPL):

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

Como dice Nicolás, interior no es un tipo, por lo que no se puede utilizar como tal.

Tratar de entender su motivación, me ocurrió algo similar:

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

Este es un poco inútil, ya que sería justo hacer referencia directamente a Interior - después de todo, sólo hay una de ella:

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

Supongo que lo que quieres hacer es aceptar un Inner desde cualquier instancia de Outer. Podemos comprobar el tipo de tal cosa:

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

Así que podría esperar a ser capaz de hacer algo como esto:

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

Esto, sin embargo, falla al compilar. No estoy seguro por qué. ¡Escriba alias para el rescate!

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 

supongo que es sólo una restricción del analizador que es incapaz de leer algo de la forma A#B.type. Usted podría enviar una solicitud de error.

+0

¿Es el 'tipo Inner = Inner.type' el mismo que' type Inner = this.Inner.type'? o ¿esos dos se refieren a dos tipos diferentes? –

+1

Sí, se refieren a lo mismo. – Submonoid

0

Cada Scala object tiene su propio tipo, y hay exactamente un valor de ese tipo: el objeto en sí. Por lo tanto, el tipo de un Scala object no es más útil que el tipo Unit.

Por ejemplo, supongamos que tiene un object A y declarar un método o una función que toma un A.type parámetro:

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

Desde siempre existirá exactamente un valor de tipo A.type, se pierde ninguna generalidad lugar referencia directamente dentro del método foo.

Si usted se encuentra con ganas de hacer esto, es más probable que lo que realmente quiere hacer abstracción sobre una clase rasgo o base del objeto:

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