Scala-переопределение метода класса в чертеже
Я новичок в Scala (пришел из Ruby world).
и мне было интересно понятие "черты" в Scala (которое должно быть ~похоже на модули в 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
спасибо всем вперед!
P. S в случае, если вам интересно "почему?", просто предположим, что система будет содержать много сущностей, которые требуют пароля (и, потенциально, безопасного пароля), поэтому черта может использоваться во многих местах.
5 ответов
конфликт между двумя определениями методов заключается в том, что вы не сделали их "одним и тем же методом". Все, что вы сделали, это сделали их совпадающими с тем же именем, аргументами и типом возврата.
чтобы сделать их действительно одним и тем же методом, чтобы один мог переопределить другой, определите их в том же месте:
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
, а затем переопределяется (вместо doppleganged или duck-typed) в User
и SecurePassword
, Scala понимает, что это действительно тот же метод, который переопределяется. Таким образом, когда вы смешиваете в SecurePassword
, он может переопределить password()
метод User
.
В дополнение к моему предыдущему ответу - совершенно другой способ получить то, что вы хотите передать функцию пароля в класс пользователя, а не через черты характера:
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)
Update: тем не менее, я думаю, что ответ Дэна Гетца, вероятно, ближе к тому, что вы изначально просили
примечание: что касается сообщения об ошибке, есть до выпуск 128 "нет ошибки неоднозначности при наследовании конфликтующего члена от метода java по умолчанию"
он должен быть разрешен в scala 2.12.х совершить 3a3688f64
SD-128
исправить переопределение проверки дляdefault
методыпроверка наследования двух конфликтующих членов была неправильной по умолчанию методы, приводящие к отсутствию сообщения об ошибке.
мы также не выдавали модификатор "needs" override " при переопределении метод по умолчанию.