Scala -覆盖trait中的类方法

pcww981p  于 2023-06-23  发布在  Scala
关注(0)|答案(6)|浏览(145)

我是Scala的新手(来自Ruby世界)。
我对Scala中的“traits”概念很好奇(如果我理解正确的话,它应该类似于Ruby中的模块)。
这里有一个用例。
假设我有一个名为User的类,定义如下:

class User {
    def password() : String = "generating a password (default)"
}

假设我有一个trait SecurePasswords,我想用它来“覆盖”User类中定义的password方法。

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
提前感谢大家!
P.S如果你想知道“为什么?”,只要假设系统将包含许多需要密码(并且可能需要安全密码)的实体,因此可以在许多地方使用trait。

vsikbqxv

vsikbqxv1#

这两个方法定义之间的冲突是因为您没有使它们成为“同一个方法”。您所做的只是使它们巧合地具有相同的名称、参数和返回类型。
为了使它们真正成为同一个方法,以便其中一个可以覆盖另一个,请在相同的位置定义它们:

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

通过在trait HasPassword中定义,然后在UserSecurePassword中重写(而不是duppleganged或duck-typed),Scala理解这是真正被重新定义的同一个方法。因此,当您在SecurePassword中混合时,它可以覆盖User中的password()方法。

11dmarpk

11dmarpk2#

除了我之前的回答--一种完全不同的方法来获得你想要的东西是将密码函数传递到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)

如图所示,您可以使用默认参数来避免在默认情况下指定密码函数。

b4lqfgs4

b4lqfgs43#

我不确定这个用例是什么。为什么不直接在类定义中包含User,用Ruby的术语来说,就是“mixin”,SecurePasswords trait和override password呢?
来自Ruby,这可能更难得到,但Scala是一种编译语言,通常不是像这样动态/动态地更改类定义的好主意。将Scala中的类型系统视为测试代码的一种方式。越是将代码解释推迟到运行时,代码的可测试性/安全性就越低。这是Scala/Java/Haskell/...(插入编译的类型化语言)--类型系统可以在编译时捕获大量错误。好好利用这一点,不要与之抗争。
我将研究隐式参数的使用以及它们如何与traits相关/使用。
此外,如果没有更广泛的上下文,即您试图在代码中使用此模式完成的内容,则很难知道,但如果您试图实现某种适配器模式,则此链接可能对您有用。
http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html

d7v8vwbk

d7v8vwbk4#

您可以在每个示例的基础上提供不同的密码行为,如下所示-但您需要在每种情况下提供显式的trait(默认或安全):

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)

更新:然而,我认为丹·盖兹的回答可能更接近你最初的要求

nr9pn0ug

nr9pn0ug5#

注意:关于错误消息,有一个挂起的issue 128“no ambiguity error when inheriting conflicting member from java default method”。
在scala 2.12.x中应该通过commit 3a3688f64解决

修复SD-128方法的覆盖检查

对于默认方法,对继承两个冲突成员的检查是错误的,导致缺少错误消息。
当重写一个默认方法时,我们也没有发出“needs `override' modifier”。

o4hqfura

o4hqfura6#

我遇到了一个类似的挑战,略有不同的是我没有控制User类-即。它是从第三方库中拉入的。“自我类型”的方法效果很好:

class User {
  def password() : String = "generating a password (default)"
}

trait SecurePasswords { this: User =>
  override def password() : String = "generating a secure password (non-default)"
}

val a = new User
val b = new User with SecurePasswords

a.password() // generating a password (default)
b.password() // generating a secure password (non-default)

相关问题