簡體   English   中英

Scala - 覆蓋特征中的類方法

[英]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中定義,然后在UserSecurePassword重寫(而不是doppleganged或duck-typed),Scala了解這是真正重新定義的方法。 因此,當您混合使用SecurePassword ,它可以覆蓋Userpassword()方法。

除了我之前的回答 - 一種完全不同的方式來獲得你想要的是將密碼函數傳遞給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.

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