#scala #types
#scala #типы
Вопрос:
Я пытаюсь написать код, который сохраняет типизированное значение переменной. Вот пример кода:
class MethodTypeTest
{
trait TSM[T <: TSM[T]]
{
def fit(): FiM[T]
}
trait FiM[T <: TSM[_]]
{
val fitErrors = mutable.HashMap[String, Double]()
}
class TS
{
//*** Here I am saving the value of the variable after some computation.
var bestModel: Option[FiM[_]] = None
}
// Now define for SMA
class SMAM extends FiM[SMA]
{
fitErrors("RMSE") = 10
}
class SMA extends TSM[SMA]
{
override def fit() = new SMAM()
}
// Now define for DMA
class DMAM extends FiM[DMA]
{
fitErrors("RMSE") = 10.5
}
class DMA extends TSM[DMA]
{
override def fit() = new DMAM()
}
def main(args: Array[String]): Unit =
{
val ts = new TS
val sma = new SMA
val dma = new DMA
val fms: Array[FiM[_]] = Array[FiM[_]](sma.fit(), dma.fit())
val bestModel: FiM[_] = fms.minBy(m => m.fitErrors("RMSE"))
// ******** Error in below line ******
// Error:(48, 24) type arguments [_$3] do not conform to trait FiM's type parameter bounds [T <: MethodTypeTest.this.TSM[_]]
// ts.bestModel = Some(bestModel)
ts.bestModel = Some(bestModel)
}
}
Похоже, компилятор жалуется, что граница типа слишком открыта в последней строке. Я намеренно оставил открытым тип bestModel в инструкции var bestModel: Option[FiM[_]] = None
при определении class TS
, поскольку это значение будет вычислено позже для одного из FIM. Как / где я могу указать привязку к типу, чтобы это работало?
Комментарии:
1. Можете ли вы сделать
TS
неизменяемым и выделить его в результате вычисленияfms.minBy
? т.е.case class TS(bestModel: FiM[_])
и тогдаval bestModel = TS(bestModel)
?2. Фактический класс TS имеет множество других переменных, которые инициализируются, только одна переменная, которую необходимо установить позже. Вот почему я не мог использовать класс case.
Ответ №1:
Я смог скомпилировать это (с помощью scastie с использованием Scala 2.13.4), добавив в границы типов _ <: TSM[_]
везде, где у вас есть FiM[_]
аннотация типа:
class TS {
var bestModel: Option[FiM[_ <: TSM[_]]] = None
}
//...
val fms: Array[FiM[_ <: TSM[_]]] = Array(sma.fit(), dma.fit())
val bestModel: FiM[_ <: TSM[_]] = fms.minBy(m => m.fitErrors("RMSE"))
Я считаю, что это необходимо, потому что в противном случае он считает, что параметр неизвестного TSM[_]
типа массива должен совпадать с параметром val , поэтому указание, что он тоже должен быть шаблоном, позволяет избежать этого.