首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >两个同名的类型参数

两个同名的类型参数
EN

Stack Overflow用户
提问于 2010-09-20 21:18:50
回答 4查看 1.2K关注 0票数 6

我想知道为什么根据下面的例子,允许两个类型参数(名为"A")具有相同的名称("A")。我知道这是一个糟糕的类型参数命名,请不要这样做。

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

代码语言:javascript
代码运行次数:0
运行
复制
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的输出示例

代码语言:javascript
代码运行次数: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
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-09-20 23:52:00

Scala中的嵌套作用域可以自由地隐藏彼此的符号表。类型并不是你唯一能做的事情。例如:

代码语言:javascript
代码运行次数:0
运行
复制
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."
      }
    }
  }
}

其原则是作用域可以控制其名称空间。如果您愚蠢地使用它,这是有危险的(例如,我用Xa表示三个不同的东西,A表示两个--实际上,您可以用X替换除Some中必须为小写的标识符之外的所有标识符)。但在编写函数式代码时,它也有好处--您不必担心因为碰巧将其放在不同的上下文中而不得不重命名某个迭代变量或类型或其他任何东西。

代码语言:javascript
代码运行次数:0
运行
复制
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
}

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

票数 8
EN

Stack Overflow用户

发布于 2010-09-20 23:04:43

我不是Scala专家,但是您的代码的行为完全符合我的期望。

首先,您需要知道方法的类型参数不需要绑定到类。

例如,下面是有效的Scala。

代码语言:javascript
代码运行次数:0
运行
复制
class Test1 {
    def test[A] (x: A) = println(x)
}

下面也是一个有效的Scala代码,唯一不同的是这个代码根本不使用类型A。

代码语言:javascript
代码运行次数:0
运行
复制
class Test2[A] {
    def test (x: Int) = println(x)
}

所以我认为现在很清楚了,首先你创建了一个MyTestInt的实例,这是很好的。

代码语言:javascript
代码运行次数:0
运行
复制
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@308ff65f

然后,在没有提供类型参数A的情况下调用checkStringA,Int,因为它是一个泛型函数,编译器必须推断A是什么类型。

代码语言:javascript
代码运行次数:0
运行
复制
scala> test.checkString("String",1)
Value is a String
x is not a String
res7: java.lang.String = String

注意:

在这个时间点上,Scala已经知道x必须是一个整数,并且它的类型是固定的,因为它是由MyTestInt提供的。因此,下面的代码将产生编译错误。

代码语言:javascript
代码运行次数:0
运行
复制
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")

现在编译器查看您提供的参数,并发现它是

代码语言:javascript
代码运行次数:0
运行
复制
checkString ("String", 1)

它对应于

代码语言:javascript
代码运行次数:0
运行
复制
checkString (value: A, x: Int)

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

代码语言:javascript
代码运行次数:0
运行
复制
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)
                          ^    
票数 4
EN

Stack Overflow用户

发布于 2010-09-20 21:50:21

嗯,我相信在scala中我们使用与Java相同的规则,基本上我们在寻找Java中最小的可用范围:

代码语言:javascript
代码运行次数:0
运行
复制
class Foo<T>{
   T instance;

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

将产生编译错误,因为泛型方法getInstance中声明的类型T与类Foo的参数类型不同。在Scala的情况下,我相信您会这样写

代码语言:javascript
代码运行次数:0
运行
复制
def checkString[A]

你告诉编译器,函数的行为会因提供的类型而异,但它与外部类的参数类无关。不幸的是,我现在找不到正确的地方是Scala规范。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3751823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档