在 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)
KMeans
和BisectingKMeans
都有setK
和fit
方法。我想在 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)
但是如果你因为使用了反射而有更好的选择,那么不特别推荐使用。在这种特定情况下,我会简单地在块内调用 setK
和 fit
;或者如果没有,创建你自己的 KMeans
和 BisectingKMeans
的包装器,它们实现了一个共同的特征。
创建您自己的界面并根据该界面调整实现。如果您需要将非常不同的 类(例如不同的方法名称)统一到一个通用接口中,这也将起作用。不需要使用 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()
我想做一些我觉得很简单的事情,但是我不知道怎么做。它如下:根据一些 String 变量,我想创建一个特定类型的对象。但是,底层对象具有相同的方法,因此我希望能够在创建该对象的 if 块之外使用该对象。实现它的最佳方法是什么?
为了说明我的需要,这里是代码:
var model = null
if (modelName == "KMeans") {
model = new KMeans()
} else if (modelName == "BisectKMeans") {
model = new BisectingKMeans()
}
model.setK(k)
model.fit(data)
KMeans
和BisectingKMeans
都有setK
和fit
方法。我想在 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)
但是如果你因为使用了反射而有更好的选择,那么不特别推荐使用。在这种特定情况下,我会简单地在块内调用 setK
和 fit
;或者如果没有,创建你自己的 KMeans
和 BisectingKMeans
的包装器,它们实现了一个共同的特征。
创建您自己的界面并根据该界面调整实现。如果您需要将非常不同的 类(例如不同的方法名称)统一到一个通用接口中,这也将起作用。不需要使用 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()