Scala技术问询:Trait中如何获取调用fit方法的继承Object?
在Scala Trait中引用继承它的Object:针对最大似然估计模型的解决方案
在Scala里要实现Trait引用继承它的Object,其实核心思路是让每个继承Trait的Object主动提供自身的引用——毕竟Trait本身没法直接知道到底是哪个具体的Object在调用它。咱们结合你提到的最大似然估计场景来一步步实现:
首先,先定义拟合结果的case class,它需要持有模型实例和估计出的参数:
case class MaximumLikelihoodFit[M](model: M, params: Map[String, Double])
接下来定义核心的Trait MaximumLikelihoodEstimation,这里我们需要加一个抽象成员,让每个实现的Object返回自己。这样Trait的fit方法就能拿到具体的模型实例了:
trait MaximumLikelihoodEstimation { // 抽象成员:要求实现类返回自身实例 def modelInstance: this.type def fit(data: Seq[Double]): MaximumLikelihoodFit[this.type] = { // 这里写你的参数估计逻辑,下面是个简单的均值方差估计示例 val mean = data.sum / data.length val variance = data.map(x => math.pow(x - mean, 2)).sum / data.length val params = Map("mean" -> mean, "variance" -> variance) // 用modelInstance拿到当前调用fit的Object,封装成结果返回 MaximumLikelihoodFit(modelInstance, params) } }
然后写你的具体模型Object,只需要实现那个抽象的modelInstance,直接返回this就行:
object ModelA extends MaximumLikelihoodEstimation { override val modelInstance: ModelA.type = this } object ModelB extends MaximumLikelihoodEstimation { override val modelInstance: ModelB.type = this }
现在测试一下:
val sampleData = Seq(1.2, 2.3, 3.1, 4.0, 5.4) val fitResult = ModelA.fit(sampleData) // fitResult 就是 MaximumLikelihoodFit(ModelA, Map("mean" -> 3.2, "variance" -> 2.184))
为啥要这么做?因为Scala的Trait可以被class和Object同时继承,Trait本身没有办法直接获取到调用它的实例类型和引用,所以通过抽象成员让每个实现者主动提供自身,就能完美解决你的需求——替代你原来设想的this.getObject,其实就是让每个Object把this暴露给Trait用。
另外,如果你觉得每次写override val modelInstance有点繁琐,也可以把抽象成员改成def,实现起来更简洁:
trait MaximumLikelihoodEstimation { def modelInstance: this.type // fit方法逻辑同上... } object ModelA extends MaximumLikelihoodEstimation { override def modelInstance: ModelA.type = this }
这样就完全满足你想要的ModelA.fit返回包含ModelA自身实例的拟合结果的需求啦。
内容的提问来源于stack exchange,提问作者Nick Resnick
相关产品推荐
相关产品推荐

