我是Scala的新手(来自Ruby世界) .
而且我对Scala中的“traits”概念感到好奇(如果我理解正确的话,它应该〜类似于ruby中的模块) .
这是一个用例 .
假设我有一个名为 User
的类,定义如下:
class User {
def password() : String = "generating a password (default)"
}
并假设我有一个特性 SecurePasswords
使用我想"override"在 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
谢谢大家!
如果你想知道“为什么?”,只要假设系统包含许多需要密码的实体(可能还有安全密码),那么这个特性可以在很多地方使用 .
5 回答
两种方法定义之间的冲突是因为您没有使它们成为“相同的方法” . 你所做的就是让它们巧合地拥有相同的名称,参数和返回类型 .
要使它们真的是相同的方法,以便可以覆盖另一个,在同一个地方定义它们:
通过在特征
HasPassword
中定义,然后在User
和SecurePassword
中重写(而不是doppleganged或duck-typed),Scala理解这是真正重新定义的方法 . 因此,当您在SecurePassword
中混合时,它可以覆盖User
中的password()
方法 .除了我之前的回答 - 一种完全不同的方式来获得你想要的是将密码函数传递给User类,而不是使用traits:
如图所示,您可以使用默认参数来避免在默认情况下指定密码函数 .
我不确定这个用例是什么 . 为什么不在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
您可以在每个实例的基础上提供不同的密码行为,如下所示 - 但您需要在每种情况下提供显式特征(默认或安全):
更新:但是,我认为Dan Getz的答案可能更接近您最初的要求
注意:关于错误消息,有待处理的issue 128 "no ambiguity error when inheriting conflicting member from java default method"
它应该在scala 2.12.x中由commit 3a3688f64解决