簡體   English   中英

特征/類類型參數優先於方法類型參數的規則是什么

[英]What are the rules for when trait/class type parameters take precedence vs method type parameters

我已經使用scala一段時間了,我以為我真的開始了解一切(嗯,大多數事情...),但是我發現自己對Map類中的許多方法定義感到困惑。 我知道foldLeft等如何工作,但是我感到困惑的是Map函數中使用的類型參數。 讓我們以foldLeft為例:

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

Map特征本身的定義采用兩個類型參數“ A”和“ B”(例如Map [A​​,+ B])。 據我所知,當使用與類/特征的類型參數之一相同的名稱為方法定義類型參數時,它將覆蓋類/特征值。 以Foo的這個定義為例:

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”來自特征定義。 例如:

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”與特征的“ B”匹配,但是如果我將函數的“ B”類型更改為String而不是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):

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定義如下:

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

對我來說,這將更清楚,但這種方式並未定義。 那么,有沒有人知道何時方法參數將覆蓋trait / class參數以及何時不覆蓋trait / class參數的規則?

在這方面,Scala與Java相同,並且Java規范的“名稱”一章中以下內容適用:

一個名為n型的聲明d陰影任何其他類型的命名n表示在范圍在其中d發生在整個d的范圍的點的聲明。

因此,方法的類型參數將始終隱藏具有相同名稱的類或特征類型參數。 您的Foo示例演示了這一事實。

正如您所鏈接的問題的答案所指出的那樣 ,在MapfoldLeft案例中,您看到的明顯反例只是當前Scaladoc版本的令人不快的工件 foldLeft沒有在Map特征中定義,但是在TraversableOnce ,根本沒有名為B的特征類型參數。

當然,通常在方法中隱藏特征或類的類型參數是一個非常糟糕的主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM