在 if 中构造的 Scala 对象

Scala objects constructed inside if

我想做一些我觉得很简单的事情,但是我不知道怎么做。它如下:根据一些 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 class 的通用对象并将变量声明为 Any 类型,但无法让它工作,实现我的目标的最佳方法是什么'我在找什么?

为了调用方法 .setK().fit(),编译器必须“知道”变量 model 是具有这些方法的特定类型。你试图说,“变量 可能 是这种类型或者它 可能 是那种类型,但它们都有这些方法所以没关系。 “

编译器不这么认为。它说,“如果它可能是 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()

Scala 实际上 确实 允许您使用 structural types:

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()