2010-09-20 11 views
6

Me pregunto por qué los dos parámetros de tipo (llamados "A") con el mismo nombre ("A") están permitidos según el ejemplo a continuación. Sé que este es un mal nombre de los parámetros de tipo, no hagas esto.dos parámetros de tipo con el mismo nombre

(Mi conjetura es que están en un nivel en un ámbito diferente, por ejemplo, el nivel de clase y la función de nivel, y el compilador está utilizando algún tipo de renombrado de nombres)

class MyTest[A](){ 
    type MyType = A 

    def checkString[A](value:A, x:MyType):A = { 
     value match { 
     case x:String => println("Value is a String") 
     case _ => println("Value is not a String") 
     } 

     x match { 
      case x:String => println("x is a String") 
      case _ => println("x is not a String") 
     } 

     value 
    } 
} 

Ejemplo de salida de 2.8.0

scala> val test = new MyTest[Int] 
test: MyTest[Int] = [email protected] 

scala> test.checkString("String",1) 
Value is a String 
x is not a String 
res7: java.lang.String = String 

scala> test.checkString(1,1) 
Value is not a String 
x is not a String 
res8: Int = 1 
+1

Esta pregunta se hace bastante más difícil de leer debido a su formateo - el corsé de cierre para el bloque de def y el código debajo de él realmente deberían estar sangrados. – Submonoid

Respuesta

8

Los telescopios anidados en Scala son libres de sombrear las tablas de símbolos de los demás. Los tipos no son las únicas cosas con las que puedes hacer esto. Por ejemplo:

class X[A](a: A) { 
    def X[A](a: A) { 
    if (a==this.a) { 
     val X = Some(this.a) 
     X match { 
     case Some(a) => "Confused much yet?" 
     case _ => "Just because you can do this doesn't mean you should." 
     } 
    } 
    } 
} 

El principio es que un ámbito tiene control sobre su espacio de nombres. Esto tiene peligros, si lo usa tontamente (por ejemplo, he utilizado X y a para cada una de tres cosas diferentes, y A para dos - de hecho, puede reemplazar cada identificador con X excepto por el uno en el cual Some tiene que ser minúscula). Pero también tiene beneficios al escribir código funcional: no tiene que preocuparse por tener que cambiar el nombre de alguna variable iterativa o escribir, o lo que sea, simplemente porque lo coloca en un contexto diferente.

def example = { 
    val a = Array(1,2,3,4,5) 
    val sumsq = a.map(i => i*i).sum 
    a.map(i => { 
    val a = Array.range(1,i) 
    val sumsq = a.map(i => i*i).sum // Cut and paste from above, and works! 
    sumsq + i 
    }).sum 
} 

Así que tenga en cuenta que usted tiene el poder para confundir a ti mismo, y sabiamente optar por utilizar ese poder no confusamente.

+1

gracias, ¿entonces la referencia es ScalaReference capítulo 2? – oluies

+0

@Brent - No recuerdo dónde lo leí o aprendí esto; Esperaría que uno pudiera extraerlo de la especificación del idioma, pero estoy bastante seguro de haberlo encontrado en un formato más conversacional. –

0

No es solo relacionado con scala. En la mayoría de los idiomas puedes hacer eso. Porque como dijiste las variables están en diferente alcance.

en C#

class test 
{ 
     int i; 
     void method(int i) 
     { 
      this.i = i; 
     } 
} 

Esto representa el tipo auto. No estoy seguro acerca de esta funcionalidad en Scala. Pero el motivo de su pregunta es el nivel de alcance.

+3

Pregunta sobre los parámetros Tipo. Para ser específico [A]. –

1

Bueno Me creer en Scala utilizamos misma regla que en Java, básicamente, estamos buscando más pequeño alcance disponibles en Java:

class Foo<T>{ 
    T instance; 

    void <T> T getInstance(){ 
     return instance 
    } 
} 

producirá un error de compilación ya que el tipo T declarada en getInstance método genérico no es el lo mismo que el tipo de parámetro de la clase Foo. En caso de Scala Creo entonces escribir

def checkString[A] 

Usted compilador diciendo que funcione el comportamiento puede variar dependiendo del tipo previsto pero no tiene ninguna relación con la clase de parámetros de la clase externa. Lamentablemente, no puedo encontrar el lugar correcto para las especificaciones de Scala en este momento.

4

No soy un experto de Scala, pero su código se comporta exactamente como esperaba.

En primer lugar, debe saber que el parámetro de tipo de método no es necesario vincularlo a la clase.

Por ejemplo, el siguiente es válido Scala.

class Test1 { 
    def test[A] (x: A) = println(x) 
} 

Y la siguiente es también un código Scala válida, la única diferencia es que éste no utiliza el tipo A en absoluto.

class Test2[A] { 
    def test (x: Int) = println(x) 
} 

así que creo que es claro ahora, primero que ha creado una instancia de MyTest [Int], lo cual está bien.

scala> val test = new MyTest[Int] 
test: MyTest[Int] = [email protected] 

Entonces llamaron checkString [A, Int] sin proporcionar parámetro de tipo A, ya que es una función genérica, el compilador debe inferencia qué tipo es A.

scala> test.checkString("String",1) 
Value is a String 
x is not a String 
res7: java.lang.String = String 

Nota:

En este punto de tiempo, Scala ya sabe que x debe ser un Int y su tipo es fijo, ya que lo proporciona MyTest [Int]. Por lo tanto, el siguiente código arrojará un error de compilación.

scala> val t = new MyTest[Int] 
t: MyTest[Int] = [email protected] 

scala> t.checkString ("A", "B") 
<console>:8: error: type mismatch; 
found : java.lang.String("B") 
required: t.MyType 
     t.checkString ("A", "B") 

Ahora el compilador mira a los argumentos que nos ha facilitado, y encontró su es

checkString ("String", 1) 

que se corresponde con

checkString (value: A, x: Int) 

Así que ahora compilador sabe tipo A en checkString [A, Int] debe ser una cadena, y si haces todo esto a mano, tu código se verá así.

scala> val test = new MyTest[Int] 
test: MyTest[Int] = [email protected] 

scala> test.checkString[String]("String", 1) 
Value is a String 
x is not a String 
res1: String = String 

scala> test.checkString[Int] (3, 4) 
Value is not a String 
x is not a String 
res4: Int = 3 

scala> test.checkString[Int] ("String", 4) 
<console>:8: error: type mismatch; 
found : java.lang.String("String") 
required: Int 
     test.checkString[Int] ("String", 4) 
         ^ 
+0

gracias, entiendo mucho, estoy un poco sorprendido de que tanto los alias para la clase como el método tengan permitido el nombre A mientras no tienen conexión entre ellos – oluies

+0

Ya, porque el A en checkString [A] sombreado la A de MyTest [A]. Al igual que el mismo nombre de variable en un bloque interno. –

Cuestiones relacionadas