trait/class 类型参数优先于方法类型参数时的规则是什么 [英] What are the rules for when trait/class type parameters take precedence vs method type parameters

查看:72
本文介绍了trait/class 类型参数优先于方法类型参数时的规则是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用 Scala 有一段时间了,我以为我真的开始理解一切(好吧,大多数事情......),但我发现自己对 Map 类中的许多方法定义感到困惑.我知道 foldLeft 等是如何工作的,但让我感到困惑的是 Map 函数中使用的类型参数.我们以 foldLeft 为例:

I've been using scala for a while now and I thought I was really starting to understand everything (well, most things...), but I found myself confused by a number of the method definitions in the Map class. I know how foldLeft, etc work, but what I'm confused about is the type parameters used in the Map functions. Let's use foldLeft as an example:

foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B

Map trait 本身的定义采用两个类型参数A"和B"(例如 Map[A,+B]).据我所知,当您使用与类/特征的类型参数之一相同的名称为方法定义类型参数时,它会覆盖类/特征值.以Foo的这个定义为例:

The definition for the Map trait itself takes two type parameters 'A' and 'B' (e.g. Map[A,+B]). From what I can tell, when you define a type parameter for a method using the same name as one of the type parameters for the class/trait, it overrides the class/trait value. Take this definition of Foo as an example:

class Foo[A : Manifest, B : Manifest] {
  def isAString() = manifest[A] == manifest[String]
  def isAInt() = manifest[A] == manifest[Int]
  def isBString() = manifest[B] == manifest[String]
  def isBInt() = manifest[B] == manifest[Int]
  def nowIsBString[B : Manifest] = manifest[B] == manifest[String]
}

scala> val f = new Foo[String,Int]
f: Foo[String,Int] = Foo@7bacb41

scala> f.isAString
res290: Boolean = true

scala> f.isAInt
res291: Boolean = false

scala> f.isBString
res292: Boolean = false

scala> f.isBInt
res293: Boolean = true

scala> f.nowIsBString[String]
res294: Boolean = true

scala> f.nowIsBString[Int]
res295: Boolean = false

所以在 foldLeft 定义中,'B' 来自方法定义,'A' 来自特征定义.例如:

So in the foldLeft definition, 'B' comes from the method definition and 'A' comes from the trait definition. For example:

val xm = Map("test" -> 1, "test2" -> 2)

scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2 
foldFn: (Int, (String, Int)) => Int = <function2>

scala> m.foldLeft(0)(foldFn)
res298: Int = 3

正如预期的那样,函数的 'B' 匹配 trait 的 'B',但是如果我将函数的 'B' 类型更改为 String 而不是 Int 会怎样:

This is as expected as 'B' for the function matches 'B' for the trait, but what if I change the 'B' type for the function to String instead of Int:

scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2 
foldFn: (String, (String, String)) => java.lang.String = <function2>

scala> m.foldLeft("")(foldFn)
<console>:19: error: type mismatch;
 found   : (String, (String, String)) => java.lang.String
 required: (java.lang.String, (java.lang.String, Int)) => java.lang.String
              m.foldLeft("")(foldFn)

那么让我们将 kv 参数更改为 (String, Int):

So let's change the kv parameter to (String, Int):

scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2 
foldFn: (String, (String, Int)) => java.lang.String = <function2>

scala> m.foldLeft("")(foldFn)
res299: java.lang.String = 12

与我的 Foo 示例不同,在这种情况下,Map 的B"值优先于函数定义,但仅适用于 kv 参数.我所期望的是看到 foldLeft 定义如下:

Unlike my Foo example, in this case the Map's 'B' value is taking precedence over the functions definition, but only for the kv parameter. What I would have expected is to see a foldLeft defined as follows:

foldLeft[C] (z: C)(op: (C, (A, B)) => C): C

这对我来说会更清楚,但它不是这样定义的.那么有谁知道方法参数何时会覆盖特征/类参数以及何时不会覆盖的规则?

That would be more clear to me, but it is not defined this way. So does anyone know the rules for when a methods parameter will override a trait/class parameter and when it will not?

推荐答案

Scala 在这方面与 Java 相同,以下来自 Java 规范适用:

Scala is the same as Java in this respect, and the following from the "Names" chapter of the Java specification applies:

一个名为 n 的类型的声明 d 遮蔽了任何其他名为 n 的类型在 d 发生的点的范围内在d的整个范围内.

A declaration d of a type named n shadows the declarations of any other types named n that are in scope at the point where d occurs throughout the scope of d.

因此,方法的类型参数将始终隐藏具有相同名称的类或特征类型参数.您的 Foo 示例演示了这一事实.

So the type parameter for a method will always shadow a class or trait type parameter with the same name. Your Foo example demonstrates this fact.

您在 MapfoldLeft 中看到的明显反例只是 令人不快的 Scaladoc 版本 在您链接的问题的答案中指出.foldLeft 没有在 Map trait 中定义,而是在 TraversableOnce,其中根本没有名为 B 的特征类型参数.

The apparent counterexample you're seeing in the case of Map's foldLeft is just an unpleasant artifact of the current version of Scaladoc, as is pointed out in the answers to the question you've linked. foldLeft isn't defined in the Map trait, but in TraversableOnce, where there isn't a trait type parameter named B at all.

通常,在方法中隐藏特征或类的类型参数是一个非常糟糕的主意,当然.

In general shadowing the type parameter of a trait or class in a method is a really bad idea, of course.

这篇关于trait/class 类型参数优先于方法类型参数时的规则是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆