[英]Why are classes inside Scala package objects dispreferred?
從2.10開始, -Xlint
抱怨軟件包對象內部定義的類。 但為什么? 在包對象內定義類應該完全等同於在具有相同名稱的單獨包內定義類,只是更加方便。
我認為,Scala中的嚴重設計缺陷之一是無法將除類之類的實體(例如,變量聲明,函數定義)以外的任何東西放在文件的頂層。 相反,您被迫將它們放入單獨的“包對象”(通常在package.scala
),與它們所屬的其余代碼分開,並違反了基本編程規則,即在概念上相關的代碼應在身體上也是如此。 我沒有看到任何理由說明Scala在概念上不允許在頂層允許任何在較低級別允許的東西,並且任何非類的東西都會自動放置到package對象中,因此用戶不必擔心。
例如,在我的情況下,我有一個util
包,在它下面有許多子包( util.io
, util.text
, util.time
, util.os
, util.math
, util.distances
等)將語義相關的功能,類甚至變量的異類集合進行分組。 我目前將所有各種函數,類等存儲在util
package object
中的io.scala
或text.scala
或任何文件中的package object
中。 這很好用,並且非常方便,因為可以混合使用函數和類,例如,我可以執行以下操作:
package object math {
// Coordinates on a sphere
case class SphereCoord(lat: Double, long: Double) { ... }
// great-circle distance between two points
def spheredist(a: SphereCoord, b: SphereCoord) = ...
// Area of rectangle running along latitude/longitude lines
def rectArea(topleft: SphereCoord, botright: SphereCoord) = ...
// ...
// ...
// Exact-decimal functions
class DecimalInexactError extends Exception
// Format floating point value in decimal, error if can't do exactly
formatDecimalExactly(val num: Double) = ...
// ...
// ...
}
沒有這個,我將不得不根據樂趣與類而不是語義來不便地拆分代碼。 我想,替代方法是將它們放置在普通對象中,這有點違背了將包裝對象放在首位的目的。
但為什么? 在包對象中定義類應該與在同一個名稱相同的單獨包中定義類完全相同,
精確地 語義(當前)是相同的,因此,如果您喜歡在包對象中定義類,則應該有充分的理由。 但是現實是,至少有一個很好的理由拒絕(繼續閱讀)。
除了更方便
這樣更方便嗎? 如果您這樣做:
package object mypkg {
class MyClass
}
您也可以執行以下操作:
package mypkg {
class MyClass
}
您甚至可以在此過程中保存幾個字符:)
現在,一個不讓包對象過度使用的良好而具體的理由是,當包打開時 , 包對象卻沒有 打開 。 一種常見的情況是在多個項目之間分配代碼,每個項目在同一包中定義類。 沒問題 另一方面,包對象(與任何對象一樣)是關閉的(如規范中所述:“每個包只能有一個包對象”)。 換句話說,您將只能在一個項目中定義一個包對象。 如果您嘗試在兩個不同的項目中為同一軟件包定義一個軟件包對象,則會發生不好的事情,因為您將有效地得到同一JVM類的兩個不同版本(在我們的情況下,您將得到兩個“ mypkg”。類”文件)。 根據情況的不同,您可能最終以編譯器抱怨找不到它在包對象的第一個版本中定義的內容,或者得到“錯誤的符號引用”錯誤,甚至可能是運行時錯誤。 這是包對象的一般限制,因此您必須意識到這一點。 在包對象內部定義類的情況下,解決方案很簡單:不要這樣做(因為與僅將類定義為頂級相比,您不會獲得任何實質性的收益)。 對於類型別名,vals和vars,我們沒有這樣的奢侈,因此在這種情況下,要權衡語法便利性(與在對象中定義它們相比)是否值得,然后注意不要定義重復的包對象。
對於這個語義上等效的操作為什么會產生皮棉警告,我還沒有找到好的答案。 我認為這是一個皮棉錯誤。 我發現唯一不能放置在包對象內(相對於普通包內)的是實現main
(或extends App
)的對象。
請注意,即使無法在包范圍內聲明隱式類,-Xlint也會抱怨在包對象內部聲明的隱式類。 (有關隱式類的規則,請參見http://docs.scala-lang.org/overviews/core/implicit-classes.html 。)
我想出了一個技巧,可以使包對象獲得所有好處,而不必抱怨過時。 代替
package object foo {
...
}
你可以做
protected class FooPackage {
...
}
package object foo extends FooPackage { }
工作原理相同,但沒有任何抱怨。 明確的跡象表明投訴本身是偽造的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.