2010-09-20 8 views
6

Je me demande pourquoi les deux types de paramètres (nommés "A") avec le même nom ("A") sont autorisés comme dans l'exemple ci-dessous. Je sais que c'est un mauvais choix des paramètres de type, ne faites pas cela.deux paramètres de type avec le même nom

(Je pense qu'ils sont sur un niveau de portée différente, par exemple le niveau de classe et niveau fonction, et le compilateur utilise une sorte de nom mangling)

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

de sortie Exemple 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

Cette question est rendue plus difficile à lire à cause de votre formatage - l'accolade fermante pour le bloc def et le code ci-dessous devrait vraiment être indenté. – Submonoid

Répondre

8

portées à Scala emboîtées sont libres d'ombre tables de symboles de chacun. Les types ne sont pas les seules choses que vous pouvez faire avec. Par exemple:

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

Le principe est qu'un champ a le contrôle sur son espace de noms. Cela comporte des dangers, si vous l'utilisez bêtement (par exemple, j'ai utilisé X et a pour chacune des trois choses différentes, et A pour deux - en fait, vous pouvez remplacer chaque identifiant avec X sauf celui du Some qui doit être en minuscule). Mais cela a aussi des avantages pour l'écriture de code fonctionnel - vous n'avez pas à vous soucier de devoir renommer une variable ou un type d'itération, ou tout simplement parce que vous le placez dans un contexte différent.

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 
} 

Alors, soyez conscient que vous avez le pouvoir de vous confondre, et choisir judicieusement d'utiliser ce pouvoir non prêter à confusion.

+1

merci, donc la référence est ScalaReference chapitre 2? – oluies

+0

@Brent - Je ne me souviens plus où j'ai lu ou appris ceci; Je m'attendrais à ce que l'on puisse l'extraire de la spécification de la langue, mais je suis sûr que je l'ai rencontré dans un format plus conversationnel. –

0

Ce n'est pas seulement lié à scala. Dans la plupart des langues, vous pouvez le faire. Parce que comme vous l'avez dit, les variables sont de portée différente.

En C#

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

cela représente le type d'auto. Je ne suis pas sûr de cette fonctionnalité dans Scala. Mais la raison de votre question est le niveau de portée.

+3

Il pose des questions sur les paramètres de type. Pour être précis [A]. –

1

Eh bien, je belive à scala, nous utilisons même règle que dans Java essentiellement que nous cherchons le plus petit champ disponible en Java:

class Foo<T>{ 
    T instance; 

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

produira une erreur de compilation car le type T a déclaré dans getInstance méthode générique est pas Identique au type de paramètre de la classe Foo. En cas de Scala, je crois vous écrire

def checkString[A] 

Vous compilateur dire que le comportement fonction varie sur le type fourni mais il n'a aucun lien avec la classe de paramètres de classe externe. Malheureusement, je ne peux pas trouver le bon endroit est Scala spec en ce moment.

4

Je ne suis pas expert de Scala, mais votre code se comporte exactement comme je l'attendais. D'abord, vous devez savoir que le paramètre type de la méthode n'a pas besoin d'être lié à la classe.

Par exemple, ce qui suit est valide Scala.

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

Et ce qui suit est également un code Scala valide, la seule différence est que celui-ci n'utilise pas le type A du tout.

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

donc je pense qu'il est clair maintenant, tout d'abord vous avez créé une instance de MyTest [Int], ce qui est bien.

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

Ensuite, vous a appelé checkString [A, Int] sans fournir le type paramètre A, car il est une fonction générique, le compilateur doit inférence ce type est A.

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

Note:

Dans ce point de temps, Scala sait déjà que x doit être un Int et son type est fixe, puisque vous le fournissez par MyTest [Int]. Donc, le code suivant donnera une erreur de compilation.

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

Maintenant, le complier regarde les arguments que vous avez fournis, et a trouvé son est

checkString ("String", 1) 

qui correspond à

checkString (value: A, x: Int) 

Alors maintenant, le compilateur sait de type A dans checkString [A, Int] doit être une chaîne, et si vous faites tout cela à la main, votre code ressemblera à ceci.

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

merci, que je comprends, je suis juste un peu surpris que les deux types alias pour la classe et la méthode est autorisé à être le nom A alors qu'ils n'ont pas de connexion les uns avec les autres – oluies

+0

Ya, parce que le A dans checkString [A] ombragé le A de MyTest [A]. Tout comme le même nom de variable dans un bloc interne. –

Questions connexes