#scala #generics #inheritance #subclass
#scala #обобщения #наследование #подкласс
Вопрос:
Я пишу программу на scala, которая использует фреймворк вокруг:
trait Tool[T <: Tool[T, U], U <: Settings[T]] {
// members here
def createSettingsFrom(settingsWithStringNames: Map[String, _]): U
}
trait Settings[T <: Tool[T, _ <: Settings[T]]
В Tool T — это подкласс, а U — класс, который несет информацию для него. Каждый инструмент можно рассматривать как своего рода команду с параметрами, и эти параметры являются пользовательскими для каждого из них.
У меня также есть класс, который расширяет его вместе с его «носителем информации»:
object Cleanup extends Tool[Cleanup, CleanupSettings] {
override def createSettingsFrom(settings: Map[String, _]): CleanupSettings
= CleanupSettings(
settings.get("attribute1").asInstanceOf[Int]
settings.get("attribute2").asInstanceOf[String])
}
case class CleanupSettings extends Settings[Cleanup](
//attribute1: Int,
//attribute2: String
//more attributes)
Когда я пытаюсь скомпилировать эти классы, я получаю следующий stacktrace:
Information:21/10/16 03:20 - Compilation completed with 2 errors and 0 warnings in 3s 200ms
/project_folder/src/main/scala/io/oreville/maptools/operations/cleanup/Cleanup.scala
Error:(17, 24) type arguments [package.tools.operations.cleanup.Cleanup,package.tools.operations.cleanup.CleanupSettings] do not conform to trait ConfigurableTool's type parameter bounds [T <: package.tools.ConfigurableTool[T,U],U <: package.tools.params.Settings[T]]
object Cleanup extends ConfigurableTool[Cleanup, CleanupSettings] {
^
/project_folder/src/main/scala/io/oreville/maptools/operations/cleanup/CleanupSettings.scala
Error:(11, 11) type arguments [package.tools.operations.cleanup.Cleanup] do not conform to trait Settings's type parameter bounds [T <: package.tools.Tool[T, _ <: package.tools.params.Settings[T]]]
extends Settings[Cleanup]
^
У меня также есть trait ConfigurableTool, который является просто расширением инструмента с некоторой дополнительной функциональностью, поэтому он имеет точно такую же общую подпись, и это просто extends Tool[T, U]
.
Я перепробовал множество способов решения проблемы, включая добавление комбинаций и — к моим обобщениям для со- и контравариантности, но это не помогает. Я рассматривал возможность использования динамического типа для своих настроек, но скорость немного влияет. Я даже не знаю, решило бы это проблему, если бы я это сделал.
Вот и все, я надеюсь, что у вас есть немного времени, чтобы помочь моему делу, если нет, все равно спасибо за чтение!
Ответ №1:
Я не могу воспроизвести полученное вами сообщение об ошибке.
В коде есть несколько опечаток, но после их устранения осталась единственная ошибка — в определении Cleanup
, которое вы не можете передать в качестве параметра типа при расширении признака.
object Cleanup extends Tool[Cleanup.type, CleanupSettings] { ... }
незаконная циклическая ссылка, включающая очистку объекта
Вы можете обойти это, сделав это признаком и расширив его в сопутствующем объекте. Вот полный код:
trait Tool[T <: Tool[T, U], U <: Settings[T]] {
// members here
def createSettingsFrom(settingsWithStringNames: Map[String, _]): U
}
trait Settings[T <: Tool[T, _ <: Settings[T]]]
trait Cleanup extends Tool[Cleanup, CleanupSettings] {
override def createSettingsFrom(settings: Map[String, _]): CleanupSettings = CleanupSettings(
settings.get("attribute1").asInstanceOf[Int],
settings.get("attribute2").asInstanceOf[String])
}
object Cleanup extends Cleanup
case class CleanupSettings(
attribute1: Int,
attribute2: String) extends Settings[Cleanup]
Комментарии:
1. О, это очень круто. В итоге я удалил параметр типа подкласса, чтобы упростить его. Я понял, что ссылаться на очистку — это не то же самое, что ссылаться на его класс, но это хороший обходной путь для циклической ссылки. Спасибо 🙂