代码之家  ›  专栏  ›  技术社区  ›  oluies

两个同名的类型参数

  •  6
  • oluies  · 技术社区  · 14 年前

    (我猜它们在不同的作用域级别上,例如类级别和函数级别,并且编译器正在使用某种名称损坏)

    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 回复  |  直到 12 年前
        1
  •  8
  •   Rex Kerr    14 年前

    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 每一个 标识符 除了那辆车里的那辆 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
    }
    

    所以要意识到你有迷惑自己的能力,明智地选择不迷惑地使用这种能力。

        2
  •  4
  •   Brian Hsu    14 年前

    我不是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)
    

    所以现在编译器知道checkString[A,Int]中的类型A必须是一个字符串,如果您手工完成所有这些,您的代码将如下所示。

    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)
                              ^    
    
        3
  •  1
  •   Nikolay Ivanov    14 年前

    class Foo<T>{
       T instance;
    
       void <T> T getInstance(){
           return instance
        }
    }
    

    将产生编译错误,因为泛型方法getInstance中声明的类型T与类Foo的参数类型不同。

    def checkString[A]
    

        4
  •  0
  •   RameshVel    14 年前

    它不仅仅与scala有关。在大多数语言中你都能做到。因为正如你所说的,变量在不同的范围内。

    在c中#

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

    这表示self类型。我不确定scala中的这个功能。但你提出这个问题的原因是范围级别。