在if内部构造的Scala对象



我想做一些我觉得很简单的事情,但我不知道怎么做。它是:根据一些String变量,我想创建一个特定类型的对象。但是,底层对象具有相同的方法,因此我希望能够在创建对象的if块之外使用此对象。实现这一目标的最佳方式是什么?

为了满足我的需求,这里有代码:

var model = null
if (modelName == "KMeans") {
model = new KMeans()
} else if (modelName == "BisectKMeans") {
model = new BisectingKMeans()
}
model.setK(k)
model.fit(data)

KMeansBisectingKMeans都具有setKfit方法。我想在if块内部创建对象,但在它外部使用对象。这段代码在声明变量时出错,因为我没有初始化它。

我尝试过使用case类的泛型对象,并将变量声明为Any类型,但无法实现这一点,实现我想要的目标的最佳方法是什么?

Scala实际上允许您使用结构类型来实现这一点:

type Model = { 
def setK(k: Int): Any
// the links in the question don't have a fit method
def fit(???): ???
}
val model: Model = if (modelName == "KMeans") { new KMeans() } else { model = new BisectingKMeans() }
model.setK(k)
model.fit(data)

但是,如果由于使用反射而有更好的替代方案,则不特别建议使用它。在这种特定情况下,我将简单地调用块内的setKfit;或者,如果没有,创建您自己的KMeansBisectingKMeans包装器,它们实现了一个共同的特性。

创建您自己的接口,并根据该接口调整实现。如果您需要将非常不同的类(例如,不同的方法名(统一到一个公共接口中,这也会起作用。不需要使用implicit def,但可以将包装部分保存在呼叫站点

trait Model {
def setK(): ??? // fill in your type
def fit(): ??? // fill in your type
}
object Model {
implicit def kmeansModel(kmean: Kmeans): Model = new Model {
def setK() = kmeans.setK() // delegate to actual Kmeans
def fit() = kmeans.fit() // delegate to actual Kmeans
}

implicit def bisectingKmeansModel(): Model = ??? // similarly
// usage
val model: Model = if (modelName == "KMeans") {
new KMeans()
} else if (modelName == "BisectKMeans") {
new BisectingKMeans()
} else {
??? // other cases
}
model.setK()
model.fit()

为了调用方法.setK().fit(),编译器必须"知道";变量CCD_ 13是具有这些方法的特定类型。你想说;变量可能是这个类型,也可能是那个类型,但它们都有这些方法,所以没关系">

编译器并不这么认为。上面写着:;如果它可能是A,也可能是B,那么它必须是LUB(最小上界(,即它们都继承自的最接近的类型">

这里有一种方法可以实现你想要的。

class KMeans {  //parent type
def setK(): Unit = ???
def fit(): Unit = ???
}
class BisectingKMeans extends KMeans {
override def setK(): Unit = ???
override def fit(): Unit = ???
}
val model =
if (modelName == "KMeans")
new KMeans()
else //always end with "else", never "else if"
new BisectingKMeans()
model.setK()
model.fit()

最新更新