[英]Scala - override a class method in a trait
我是Scala的新手(來自Ruby世界)。
而且我對Scala中的“traits”概念感到好奇(如果我理解正確的話,它應該〜類似於ruby中的模塊)。
這是一個用例。
假設我有一個名為User
的類,如下所示:
class User {
def password() : String = "generating a password (default)"
}
假設我有一個特性SecurePasswords
,我想用它“覆蓋” User
類中定義的密碼方法。
trait SecurePasswords {
def password() : String = "generating a secure password (non-default)"
}
並且,假設我希望它適用於User
類的實例,而不適用於整個類本身。
val a = new User
val b = new User with SecurePasswords
a.password() # generating a password (default)
b.password() # generating a secure password (non-default)
現在這是一個理想的輸出,我期望,但是,我得到不同的錯誤,如“ anonymous class inherits conflicting members ... (Note: this can be resolved declaring etc etc ...)
”
這可以在Scala中完成,或者我要求太多/做一些非常奇怪的事情? 是否可以執行任何其他類定義,例如UserWithSecurePassword extends User
謝謝大家!
PS如果您想知道“為什么?”,只需假設系統中包含許多需要密碼的實體(可能還有安全密碼),因此可以在很多地方使用該特征。
兩種方法定義之間的沖突是因為您沒有使它們成為“相同的方法”。 你所做的就是讓它們巧合地擁有相同的名稱,參數和返回類型。
要使它們真的是相同的方法,以便可以覆蓋另一個,在同一個地方定義它們:
trait HasPassword {
def password(): String
}
class User extends HasPassword {
override def password(): String = "generating a password (default)"
}
trait SecurePassword extends HasPassword {
override def password(): String = "generating a password (non-default)"
}
new User with SecurePassword
通過在特征HasPassword
中定義,然后在User
和SecurePassword
重寫(而不是doppleganged或duck-typed),Scala了解這是真正重新定義的方法。 因此,當您混合使用SecurePassword
,它可以覆蓋User
的password()
方法。
除了我之前的回答 - 一種完全不同的方式來獲得你想要的是將密碼函數傳遞給User類,而不是使用traits:
class User(pw: ()=>String=default) {
def password = pw
}
val default = () => "generating a password (default)"
val secure = () => "generating a secure password (non-default)"
val a = new User()
val b = new User(secure)
a.password() // generating a password (default)
b.password() // generating a secure password (non-default)
如圖所示,您可以使用默認參數來避免在默認情況下指定密碼函數。
我不確定這個用例是什么。 為什么不在Ruby中使用“mixin”,SecurePasswords特征並覆蓋其類定義中的密碼?
來自Ruby,這可能更難獲得,但Scala是一種編譯語言,並且像這樣動態/動態更改類定義通常不是一個好主意。 將Scala中的類型系統視為一種測試代碼的方式。 將代碼解釋推遲到運行時越多,代碼的可測試性/安全性就越低。 這是Scala / Java / Haskell / ...(插入編譯的類型語言)的優勢之一 - 類型系統可以在編譯時捕獲大量錯誤。 使用這個對你有利,不要反對它。
我將研究隱式參數的使用以及它們如何與特征相關/使用。
此外,如果沒有使用此模式在代碼中嘗試完成的更廣泛的上下文,則很難知道,但是如果您嘗試實現某種適配器模式,則此鏈接可能對您有用。
http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html
您可以在每個實例的基礎上提供不同的密碼行為,如下所示 - 但您需要在每種情況下提供顯式特征(默認或安全):
abstract class User {
def password(): String
}
trait SecurePasswords {
def password(): String = "generating a secure password (non-default)"
}
trait DefaultPasswords {
def password(): String = "generating a password (default)"
}
val a = new User with DefaultPasswords
val b = new User with SecurePasswords
a.password() // generating a password (default)
b.password() // generating a secure password (non-default)
更新:但是,我認為Dan Getz的答案可能更接近您最初的要求
注意:關於錯誤消息,有一個待定問題128 “從java默認方法繼承沖突成員時沒有歧義錯誤”
它應該通過提交3a3688f64在scala 2.12.x中解決
SD-128
修復了對default
方法的覆蓋檢查對於默認方法,繼承兩個沖突成員的檢查是錯誤的,從而導致缺少錯誤消息。
當覆蓋默認方法時,我們也沒有發出“needs`overtion'修飾符”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.