我遇到了一个问题,我正在处理几个使用依赖类型的特质,但是当我尝试将特质结合到我的业务逻辑中时,出现编译错误。
import java.util.UUID
object TestDependentTypes extends App{
val myConf = RealConf(UUID.randomUUID(), RealSettings(RealData(5, 25.0)))
RealConfLoader(7).extractData(myConf.settings)
def processor(confLoader: ConfLoader, conf: Conf) = confLoader.extractData(conf.settings)
}
trait Data
case class RealData(anInt: Int, aDouble: Double) extends Data
trait MySettings
case class RealSettings(data: RealData) extends MySettings
trait Conf {
type T <: MySettings
def id: UUID
def settings: T
}
case class RealConf(id: UUID, settings: RealSettings) extends Conf {
type T = RealSettings
}
trait ConfLoader{
type T <: MySettings
type U <: Data
def extractData(settings: T): U
}
case class RealConfLoader(someInfo: Int) extends ConfLoader {
type T = RealSettings
type U = RealData
override def extractData(settings: RealSettings): RealData = settings.data
}
processor
中的代码将无法编译,因为extractData
期望输入的类型为ConfLoader.T
,但是conf.settings
的类型为Conf.T
。这些是不同的类型。
但是,我已经指定两者都必须是MySettings
的子类,因此应该在需要使用另一个的情况下使用这种情况。我了解Scala不会编译代码,但是有一些解决方法可以使conf.settings
传递到confLoader.extractData
吗?
processor
中的代码将无法编译,因为extractData
期望输入的类型为ConfLoader.T
,但是conf.settings
的类型为Conf.T
。这些是不同的类型。
在方法processor
中,您应指定这些类型相同。
为此使用type refinements:或者
def processor[_T](confLoader: ConfLoader { type T = _T }, conf: Conf { type T = _T }) =
confLoader.extractData(conf.settings)
或
def processor(confLoader: ConfLoader)(conf: Conf { type T = confLoader.T }) =
confLoader.extractData(conf.settings)
或
def processor(conf: Conf)(confLoader: ConfLoader { type T = conf.T }) =
confLoader.extractData(conf.settings)
恕我直言,如果您不需要依赖类型提供的任何功能,则应只使用普通的类型参数。
因此:
trait Conf[S <: MySettings] {
def id: UUID
def settings: S
}
final case class RealConf(id: UUID, settings: RealSettings) extends Conf[RealSettings]
trait ConfLoader[S <: MySettings, D <: Data] {
def extractData(settings: S): D
}
final case class RealConfLoader(someInfo: Int) extends ConfLoader[RealSettings, RealData] {
override def extractData(settings: RealSettings): RealData =
settings.data
}
def processor[S <: MySettings, D <: Data](loader: ConfLoader[S, D])(conf: Conf[S]): D =
loader.extractData(conf.settings)
但是,如果您确实要求他们成为类型成员,则可以确保两者相同。
def processor(loader: ConfLoader)(conf: Conf)
(implicit ev: conf.S <:< loader.S): loader.D =
loader.extractData(conf.settings)