我想知道为什么根据下面的例子,允许两个类型参数(名为"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
发布于 2010-09-20 15:52:00
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
}
所以,要意识到你有迷惑自己的能力,明智地选择不迷惑地使用这种能力。
发布于 2010-09-20 15:04:43
我不是Scala专家,但是您的代码的行为完全符合我的期望。
首先,您需要知道方法的类型参数不需要绑定到类。
例如,下面是有效的Scala。
class Test1 {
def test[A] (x: A) = println(x)
}
下面也是一个有效的Scala代码,唯一不同的是这个代码根本不使用类型A。
class Test2[A] {
def test (x: Int) = println(x)
}
所以我认为现在很清楚了,首先你创建了一个MyTestInt的实例,这是很好的。
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@308ff65f
然后,在没有提供类型参数A的情况下调用checkStringA,Int,因为它是一个泛型函数,编译器必须推断A是什么类型。
scala> test.checkString("String",1)
Value is a String
x is not a String
res7: java.lang.String = String
注意:
在这个时间点上,Scala已经知道x必须是一个整数,并且它的类型是固定的,因为它是由MyTestInt提供的。因此,下面的代码将产生编译错误。
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)
所以现在编译器知道了checkStringA中的类型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)
^
发布于 2010-09-20 13:50:21
嗯,我相信在scala中我们使用与Java相同的规则,基本上我们在寻找Java中最小的可用范围:
class Foo<T>{
T instance;
void <T> T getInstance(){
return instance
}
}
将产生编译错误,因为泛型方法getInstance中声明的类型T与类Foo的参数类型不同。在Scala的情况下,我相信您会这样写
def checkString[A]
你告诉编译器,函数的行为会因提供的类型而异,但它与外部类的参数类无关。不幸的是,我现在找不到正确的地方是Scala规范。
https://stackoverflow.com/questions/3751823
复制