два типа параметров с одинаковым именем - PullRequest
6 голосов
/ 20 сентября 2010

Мне интересно, почему два типа параметров (с именем "A") с одинаковым именем ("A") разрешены в соответствии с примером ниже.Я знаю, что это плохое именование параметров типа, не делайте этого.

(я предполагаю, что они находятся на другом уровне области видимости, например на уровне класса и на уровне функций, и компиляторкакое-то название искажения имени)

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

Пример вывода из 2.8.0

scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@308ff65f

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

Ответы [ 4 ]

8 голосов
/ 20 сентября 2010

Вложенные области в Scala могут свободно скрывать таблицы символов друг друга. Типы не единственные вещи, с которыми вы можете сделать это. Например:

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

Принцип заключается в том, что область имеет контроль над своим пространством имен. Это опасно, если вы используете его по глупости (например, я использовал X и a для каждой из трех разных вещей, и A для двух - фактически, вы можете заменить каждый идентификатор с X за исключением значения в Some, которое должно быть в нижнем регистре). Но это также имеет преимущества при написании функционального кода - вам не нужно беспокоиться о необходимости переименования какой-либо итерируемой переменной или типа или чего-то еще только потому, что вы случайно поместили ее в другой контекст.

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
}

Так что знайте, что у вас есть сила, чтобы запутать себя, и мудро решите использовать эту силу не путая.

4 голосов
/ 20 сентября 2010

Я не эксперт по Scala, но ваш код ведет себя именно так, как я ожидал.

Во-первых, вам нужно знать, что параметр типа метода не обязательно привязан к классу.

Например, следующее действительное Scala:

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

И следующее также является действительным кодом Scala, единственное отличие состоит в том, что этот код вообще не использует тип A.

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

Так что я думаю, что теперь все ясно, сначала вы создали экземпляр MyTest [Int], что нормально.

scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@308ff65f

Затем вы вызвали checkString [A, Int] без параметра предоставления типа.A, поскольку это универсальная функция, компилятор должен определить, какой тип является A.

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

Примечание:

В этот момент времени Scala уже знает, что x должен быть Int иего тип фиксирован, так как вы предоставляете его MyTest [Int].Таким образом, следующий код выдаст ошибку компиляции.

scala> val t = new MyTest[Int]
t: MyTest[Int] = MyTest@cb800f

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

Теперь компилятор просматривает предоставленные вами аргументы и обнаруживает, что это

checkString ("String", 1)

, что соответствует

checkString (value: A, x: Int)

Итак, теперь компилятор знает, что тип A в checkString [A, Int] должен быть строкой, и если вы все это сделаете вручную, ваш код будет выглядеть следующим образом.

scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@5bda13

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)
                          ^    
1 голос
/ 20 сентября 2010

Ну, я верю, что в Scala мы используем то же правило, что и в Java, в основном мы ищем наименьшую доступную область в Java:

class Foo<T>{
   T instance;

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

Произойдет ошибка компиляции, поскольку тип T, объявленный в универсальном методе getInstance, отличается от типа параметра класса Foo. В случае со Scala я верю, тогда ты пишешь

def checkString[A]

Вы сообщаете компилятору, что поведение функции будет зависеть от предоставленного типа, но оно не связано с классом параметров внешнего класса. К сожалению, сейчас я не могу найти правильное место для спецификации Scala.

0 голосов
/ 20 сентября 2010

Это не просто связано со скалой.На большинстве языков вы можете сделать это.Потому что, как вы сказали, переменные находятся в другой области видимости.

В c #

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

это представляет тип self.Я не уверен насчет этой функциональности в Scala.Но причина вашего вопроса - уровень охвата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...