我是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。
6条答案
按热度按时间vsikbqxv1#
这两个方法定义之间的冲突是因为您没有使它们成为“同一个方法”。您所做的只是使它们巧合地具有相同的名称、参数和返回类型。
为了使它们真正成为同一个方法,以便其中一个可以覆盖另一个,请在相同的位置定义它们:
通过在trait
HasPassword
中定义,然后在User
和SecurePassword
中重写(而不是duppleganged或duck-typed),Scala理解这是真正被重新定义的同一个方法。因此,当您在SecurePassword
中混合时,它可以覆盖User
中的password()
方法。11dmarpk2#
除了我之前的回答--一种完全不同的方法来获得你想要的东西是将密码函数传递到User类中,而不是使用traits:
如图所示,您可以使用默认参数来避免在默认情况下指定密码函数。
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
d7v8vwbk4#
您可以在每个示例的基础上提供不同的密码行为,如下所示-但您需要在每种情况下提供显式的trait(默认或安全):
更新:然而,我认为丹·盖兹的回答可能更接近你最初的要求
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”。
o4hqfura6#
我遇到了一个类似的挑战,略有不同的是我没有控制
User
类-即。它是从第三方库中拉入的。“自我类型”的方法效果很好: