常見問題,附有簡短答案和/或較長答案的連結。
此清單僅包含在 Scala 聊天室和論壇中實際反覆出現的問題。
一般問題
我在哪裡可以詢問 Scala 問題?
請參閱我們的 社群頁面。
有什麼關於 Scala 的好書?
我們的 書籍頁面 列出了幾本特別受歡迎、知名的書籍。
我們沒有列出所有現有的 Scala 書籍;有很多本。
您可以在 Discord 上的 #scala-users 房間或其他社群論壇上詢問書籍推薦。如果您提供一些關於您的背景和您想學習 Scala 的原因,您將獲得更有用的答案。
我應該學習 Scala 2 還是 Scala 3?
別為這個決定太過煩惱。無論如何,你都不會錯得太離譜。無論哪個方向,稍後要切換都不會太困難。
Scala 2 仍然是一個常見且合理的選擇。大多數 Scala 工作仍然是 Scala 2 工作。Scala 2 也有稍大一點的函式庫生態系統、稍好的工具支援,以及更廣泛的學習材料可用性。
話雖如此,這些差距每個月都在縮小。有許多書籍可用,一個豐富的函式庫生態系統已經存在,而且使用 Scala 3 的工作越來越多。你應該強烈考慮學習 Scala 3。它仍然相當新,於 2021 年發布。但它是未來,而且是愛上這門語言及其所提供的一切的最佳版本。
Scala 工作在哪裡刊登廣告?
這在我們的 社群頁面 上有說明。
簡而言之,唯一官方認可的地方是 Discord 上的 #jobs 頻道。
Scala 背後是誰?
這個問題在 社群頁面 上有解答。
我可以使用 Scala 標誌嗎?
技術問題
建議使用哪些編譯器標記?
可用選項清單 在此。
人們選擇的標記因商店而異,因人而異。啟用 -Xlint
是有價值的。一些勇敢的人啟用 -Werror
(以前稱為 -Xfatal-warnings
)以使警告變為致命。
sbt-tpolecat 是一個武斷的 sbt 外掛程式,它會根據 Scala 版本自動設定許多選項;你可以 在此 看到它設定了什麼。它做出的某些選擇是針對純函數程式設計師的。
如何找出某個符號的意義或作用?
一個 Stack Overflow 回答 說明了 Scala 中不同種類的符號,並解釋了最常用的符號。
Scala 允許使用符號方法名稱。因此,如果您在 Scala 程式碼中看到類似 >=@=>
的隨機運算子,它可能只是某個函式庫中的方法,而不是在語言本身中具有任何特殊含義。
您可以在 Google 上搜尋符號。例如,如果您想知道 <:<
的意思,搜尋 scala <:<
即可。如果您獲得的結果不佳,請嘗試用雙引號將符號括起來。
我想要 Scala 2.13(或其他版本);為什麼 sbt 說它正在使用 Scala 2.12?
sbt 1.x 始終使用 Scala 2.12 編譯建置定義。您的 sbt 1.x 建置定義永遠是 Scala 2.12 程式。
無論如何,在您的 build.sbt
中,您可以將 scalaVersion
設定為您想要的任何可用發行版本,您的程式碼將使用該版本編譯。
我想要 Scala 3。為什麼 versionNumberString
說我使用的是 2.13?
為了協助遷移,Scala 3 目前使用 Scala 2.13 函式庫,僅有少許補充。這就是 versionString
和 versionNumberString
報告使用 Scala 2 的原因
Welcome to Scala 3.3.2 (17.0.3, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> util.Properties.versionNumberString
val res0: String = 2.13.12
請注意,即使最新的 Scala 3 版本可能不會使用最新的 Scala 2 標準函式庫,因為 3 和 2 的發行時程並未協調。
那麼,您如何詢問 Scala 3 版本號碼?Scala 3 提供 dotty.tools.dotc.config.Properties.versionNumberString
,但前提是您的 classpath 中有 scala3-compiler。因此,這在 Scala 3 REPL 中有效,但在典型的 Scala 3 應用程式程式碼中無效。
有關偵測 Scala 3 版本的替代方法,請參閱 此 gist。
為什麼我的(抽象或覆寫)val
為 null?
請參閱 這。
我應該選擇哪種類型的集合?
請參閱 Scala 2.13 集合指南。
什麼是內容界限?
它是內容參數的語法糖(Scala 2 中的 implicit
參數,或 Scala 3 中的 using
參數)。
更多詳細資訊請參閱 Scala 3 書籍的此部分 和 此 Stack Overflow 回答。
for / yield
如何運作?
它是巢狀 map
、flatMap
和 withFilter
呼叫的語法糖。
如需深入說明,請參閱 此 Stack Overflow 回答。
檢視、串流和反覆運算器之間的差異是什麼?
_
的意思是?
實際上有很多意思,視情況而定。 Stack Overflow 上的此回答 對其所有意思有很好的摘要。
請注意,即使特定意思不同,根據情況,通常表示「任何東西」。
為什麼我的函式文字中包含 _
無法運作?
並非所有函式文字(又稱 lambda)都可以用 _
語法表示。
_
的每個出現都會引入一個新變數。因此 _ + _
表示 (x, y) => x + y
,而不是 x => x + x
。後者函式無法使用 _
語法撰寫。
此外,_
的範圍始終是最小的封閉式。範圍在解析期間純粹以語法方式決定,而不考慮類型。例如,foo(_ + 1)
始終表示 foo(x => x + 1)
;它永遠不會表示 x => foo(x + 1)
。後者函式無法使用 _
語法撰寫。
另請參閱 SLS 6.23.2。
為什麼 Scala 無法推論我程式碼中的正確類型?
很難概括類型推論,因為語言的各種功能會影響程式碼的解釋方式。可能有數種方法可以改寫程式碼,以自然地得出類型。
最直接的解決方法是在程式碼中提供明確類型。
這可能涉及為定義指定明確類型,或為方法指定類型參數。
Scala 3 中的類型推論得到了極大的改進。如果 Scala 2 無法編譯您的程式碼,那麼值得使用 Scala 3 嘗試一下。
有時,使用多個參數清單有助於推論,如 語言導覽的這一部分 中所解釋的。
有關涉及 toSet
的類型推論的常見問題,請參閱 此問題 和相關的 問答 中的討論。
我可以鏈接或巢狀隱式轉換嗎?
實際上不行,但您可以 讓它起作用。
但是,請注意,通常 不建議 使用隱式轉換。
Scala 在哪裡尋找隱式?
為什麼原始類型參數會擦除為 Object
?
因此,例如,Scala 程式碼中的 List[Int]
在 Java 中將顯示為 List[Object]
。Java 類型系統不允許原始類型顯示為類型參數,但它們不能顯示為其裝箱等價項,例如 List[java.lang.Integer]
嗎?
人們會希望如此,但嘗試這樣做,結果證明是不可能的。 這個 SO 問題 遺憾地缺乏簡潔的解釋,但它確實連結到過去的討論。
方法和函數之間有什麼區別?
例如,像這樣的
def square(x: Int): Int = x * x
方法與像這樣的
val square: Int => Int = x => x * x
函數值有什麼不同?對於 Scala 2,Stack Overflow 上有一個完整的答案 和 一個包含實際差異的摘要。
請注意,在 Scala 3 中,差異較少;例如,它們將能夠 接受隱式參數 以及 類型參數。
儘管如此,除非您絕對需要函式,否則仍建議大部分時間使用方法。而且,感謝 eta 擴充,您很少需要定義函式,而不是方法。
類型和類別之間有什麼區別?
類型主要是一個編譯時的概念。在編譯時,每個表達式都會被編譯器分配一個類型。
類別主要是一個執行時的概念,並且依賴於平台。在 JVM 上的執行時,每個值都是一個原始值或恰好一個類別的實例。
一些類型資訊僅存在於編譯時,原因有很多,最臭名昭著的是 類型擦除。
有關類型與類別的深入探討,請參閱部落格文章 “There are more types than classes”。
超類別中的方法如何傳回“當前”類型的值?
首先,請注意使用 this.type
無法正常運作。人們經常嘗試這樣做,但 this.type
的意思是“此實例的單例類型”,這是一個不同且過於具體的含義。只有 this
本身具有類型 this.type
;其他實例則沒有。
什麼有效?可能的解決方案包括 F 邊界多態性(Java 程式設計師熟悉)、類型成員和 類型類別模式。
這篇 部落格文章 反對 F 邊界,並支持類型類別;另請參閱 這篇 Stack Overflow 文章,以了解一些反論。
<:<
是什麼意思?
它是一個“類型約束”,它來自標準函式庫,而不是語言本身。請參閱 這篇部落格文章。
我不喜歡要求呼叫者將可選參數包裝在 Some(...)
中;有更好的方法嗎?
沒有。請參閱 Stack Overflow 上的這個答案。
為什麼通常建議使用 implicit val
而不是 implicit object
?
後者具有單例類型,這過於具體。請參閱 Stack Overflow 上的答案。
編譯我的程式碼時,我收到一個 StackOverflowError
。這是編譯器錯誤嗎?
可能是。
找出原因,請嘗試給編譯器更多堆疊,看看錯誤是否消失。
編譯某些種類的深度巢狀程式碼時,編譯器可能會耗盡堆疊。JVM 的預設堆疊大小相當小,因此這可能會比你預期的更快發生。
堆疊大小可以在 JVM 啟動時傳遞 -Xss...
來變更,例如 -Xss16M
。如何執行此操作取決於你使用的 IDE 和/或建置工具。對於 sbt,請將其新增到 .jvmopts
。
無論你給編譯器多少堆疊,堆疊溢位都不會消失,那麼這就是編譯器錯誤。請在 Scala 2 錯誤追蹤器 或 Scala 3 錯誤追蹤器 上回報,但請先檢查它是否與現有問題重複。
我在 sbt 中設定設定,但什麼事都沒發生。為什麼?
原因可能很多。一個極為常見的原因,幾乎每個人遲早都會遇到,就是你在多專案建置中有一個裸設定。
例如,如果你將此新增到你的 build.sbt
scalaVersion := "2.13.13"
那是一個「裸」設定,你可能會希望它套用於整個建置。但它沒有。它只套用於根專案。
在許多情況下,你應該改寫成
ThisBuild / scalaVersion := "2.13.13"
其他可能性包括
- 常見的設定模式,你將共用設定放入一個
val
,通常命名為commonSettings
,然後在每個你想要套用的專案中.settings(commonSettings)
。 - 僅在互動使用中,
set every
以下是一些進一步的閱讀