[英]Why does Scala's require method in Predef allow a String as argument?
我可以在Scala的Predef類中使用require方法,並將String作為第二個參數,例如
require ("foo" == "bar", "foobar")
首先考慮將require方法作為第二個參數重載為不同的參數。 但事實並非如此。 require方法的簽名(Scala 2.9.1)是:
require(requirement: Boolean, message: ⇒ Any): Unit
為什么上述方法調用可能?
我不完全理解這個問題,但這里有一點解釋。 require
在Predef
有一個重載版本:
def require(requirement: Boolean) //...
def require(requirement: Boolean, message: => Any) //...
由於message: => Any
,第二個有點令人困惑message: => Any
類型。 如果簡單的話可能會更容易:
def require(requirement: Boolean, message: Any) //...
第二個參數當然是一條消息,如果不滿足斷言,則假定將其附加到錯誤消息中。 您可以想象message
應該是String
類型,但是Any
可以簡單地寫:
require(x == 4, x)
如果不等於4
則會將x
( Int
類型)的實際值添加到錯誤消息中。 這就是選擇Any
的原因 - 允許任意值。
但那么: =>
部分? 這稱為名稱調用 ,基本上意味着: 在訪問它時評估此參數。 想象一下以下片段:
require(list.isEmpty, list.size)
在這種情況下,您需要確保list
為空 - 如果不是,請將實際list
大小添加到錯誤消息中。 但是,對於普通的調用約定,必須在調用方法之前評估list.size
部分 - 這可能是浪費的。 通過按名稱約定調用, list.size
僅在第一次使用時進行評估 - 當錯誤消息是構造函數(如果需要)時。
在scala具有默認參數之前, Predef
存在require
方法(在2.8中引入),因此如果您想要給定參數的默認行為,則重載是唯一的選項。 如消息所示,第二個參數可以是任何東西,然后將其用作拋出的IllegalArgumentException
的message
(通過調用其toString
方法)( 如果它被拋出 - 即如果需求失敗 )。
請注意,參數實際上是按名稱調用的 ; 也就是說,它被聲明為=> Any
,這意味着只有在需求失敗時才會對其進行評估 。
這會以對象創建的形式造成性能損失,但在消息構造昂貴的情況下(可能需要對數據結構進行一些O(n)訪問)可能會有用。
問題是,為什么String是第二個參數的有效類型,而簽名說它必須是一個函數
message: => Any
。
簽名並沒有這么說。 簽名表示第二個參數的類型為Any
,並且此參數按名稱傳遞 。
該“按姓名”由前綴指示=>
符號,其並不意味着函數-函數始終表示為輸入參數 => 結果類型 ,與Function0
是() => type
。
按“值”和“按名稱”查找參數。
答案很簡單:你期待第二個論點
require(boolean: Boolean, message: => Any): Unit
是一個函數的任何及問為什么一個String
的工作,即使它不是一個函數 。
分解為:固定String
只是一個函數
()
括號 實際上,以下兩個語句在Scala中是等效的:
def x: String = "ABC" // const value, even though 'def' implies a function
val x: String = "ABC"
所以你可能會說String
=> Any
滿足=> Any
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.