我正在尝试将java webapp转换为scala。我一直在努力解决Type Mismatch错误,这对于确定问题的原因或者我不知道如何阅读它们没有多大帮助。我试过在下面的帖子中询问整个设计中的问题,但看起来这并没有帮助我。
Scala type mismatch errors when using type classes and factory methods
所以我把我的问题分解成小块。希望这将导致最终的解决方案。有人可以帮我解决DataContext和DataContextBuilder之间的契约吗?
从上面的帖子中取出的部分:
trait DBObject
trait AggDBObject extends DBObject
trait RawDBObject extends DBObject
class Dimensions1Agg extends AggDBObject
class Dimensions2Agg extends AggDBObject
class Dimensions1Raw extends RawDBObject
trait IDataContext[A <: DBObject] {
var XsummaryData: A = _
var XByDateData : Map[String, A] = _
... more feilds ..
def restrictAccess = {.. some impl ..}
}
trait IDataContextBuilder[A <: DBObject] {
def initDataPoints(dataContext: IDataContext[A]): Unit
}
class Dimension1AggContextBuilder extends IDataContextBuilder[Dimension1Agg] {
.. override method impl..
}
object IDataContext {
def apply(sId: Int, mId: Int): DataContext[_ <: DBObject] = {
(sId, mId) match {
case (1, 1) => {
new DataContext[Dimension1Agg]()
}
case (1, 2) => {
new DataContext[Dimension1Raw]()
}
}
}
}
我正在创建的对象是否有正确的返回类型的apply方法?如果我删除它然后我在调用站点“val dataContext:DataContext [_&gt;:Dimension1Agg with Dimension1Raw&lt;:DBObject] with Product with Serializable {..}”
获得一些复杂的返回类型object IDataContextBuilder {
def apply(sId: Int, daId: Int): IDataContextBuilder[_ <: DBObject] = {
(sId, daId) match {
case (1, 1) => {
new Dimension1AggContextBuilder
}
case (1, 2) => {
new Dimension1RawContextBuilder
}
}
}
}
您是否看到上述工厂方法的一般问题?
无论如何,在将DataContext传递给DataContextBuilder
时出现以下错误类型不匹配; found:IDataContext [_ $ 1]其中type $ 1&lt ;:需要DBObject:IDataContext [ $ 19]
上面是_ $ 1和_ $ 19,因为scalac无法确定类型?
编辑:
将站点调用为接收用户请求参数的DataService类,编排所有上述组件并撰写响应。我知道它不起作用,但我正在尝试进行渐进式重构。 DataService检查请求参数,将该信息传递给工厂方法以创建多个DataContext和DataContextBuilder以及DataWorker;调用所有DataContextBuilder的initDataPoints方法,等待它们完成;调用所有Dataworker的generateView方法,等待它们完成,最后组成响应。
1)将每个度量的映射初始化为DataContext var measureToDCMap = MapInt,IDataContext [_&lt;:DBObject] 2)对于每个measuer,它执行以下操作以填充DataContext
Get concrete DataContext from its factory method
Get concrete DataContextBuilder from its factory method
Call DataContextBuilder's initDataPoints method
3)此时所有DataContext都填充了相应的DimensionData。
4)为每个矩阵的每个度量的每个视图初始化dataView映射(每天平均推文,每个主题的平均推文,推文率百分位等)
var dataView = MapInt,Map [Int,Map [Int,List [DataView]]] 5)对于每个视图,它执行以下操作以生成最终可查看响应
Get concrete ViewWorker . i.e. Metrix1ViewWorker or MetrixViewWorker
Call getData method
6)产生最终答案
答案 0 :(得分:1)
这是一种简化它的方法。我拿出了一些额外的接口等等:
trait DBObject
trait AggDBObject extends DBObject
trait RawDBObject extends DBObject
class Dimensions1Agg extends AggDBObject
class Dimensions2Agg extends AggDBObject
class Dimensions1Raw extends RawDBObject
class DataContext[A <: DBObject] {
var XsummaryData: A = _
var XByDateData : Map[String, A] = _
def restrictAccess = {
// .. some impl ..
}
}
object DataContext {
def buildDim1Agg() : DataContext[Dimensions1Agg] = {
// Put the custom code for Dim1 you had at `initDataPoints`
// ...
new DataContext[Dimensions1Agg]()
}
// Add other builder methods if you have lots of custom code, or functions shared across builders.
/** This is your main builder function.
* Note that per your request, it is not polymorphic, but tied to a specific type of DBObject. */
def apply(sId: Int, mId: Int): DataContext[_ <: DBObject] = {
(sId, mId) match {
case (1, 1) => buildDim1Agg()
case (1, 2) => buildDim1Agg()
//... add more cases and a default case.
}
}
}
您没有发布会调用所有这些内容的代码,并且缺少某些上下文,所以我做了很多假设。
特别是,如果你愿意在这里做实际的OOP,你可以将每个DBObject类的自定义代码移动到该特定类的构造函数中(每个类都知道如何初始化自己)并拥有一个更通用的DataContext关心它存储的具体类型:
trait DBObject
trait AggDBObject extends DBObject
trait RawDBObject extends DBObject
class Dimensions1Agg extends AggDBObject {
// Put the custom code you had at `initDataPoints`
}
class Dimensions2Agg extends AggDBObject {
// Put the custom code you had at `initDataPoints`
}
class Dimensions1Raw extends RawDBObject {
// Put the custom code you had at `initDataPoints`
}
class DataContext(var summaryData: DBObject) {
var XByDateData : Map[String, DBObject] = _
def restrictAccess = {
// .. some impl ..
}
}
object DataContext {
/** This is your main builder function.
* This version IS polymorphic, your data context holds a DBObject of the right type, but callers don't need to know which one. */
def apply(sId: Int, mId: Int): DataContext = {
(sId, mId) match {
case (1, 1) => new DataContext(new Dimensions1Agg())
case (1, 2) => new DataContext(new Dimensions2Agg())
//... add more cases and a default case.
}
}
}
希望它有所帮助。
答案 1 :(得分:0)
无论如何,在将DataContext传递给DataContextBuilder
时出现以下错误type mismatch; found : IDataContext[_$1] where type $1 <: DBObject required: IDataContext[$19] is _$1 and _$19 because scalac can't determine types?
在这种情况下,DataContext.apply
可以返回DataContext[Dimension1Agg]
,IDataContextBuilder.apply
返回Dimension1RawContextBuilder
。如果您将相同的参数传递给两者,则不会发生这种情况,但类型允许它,因此scalac正确拒绝该程序。我在这种情况下所做的是避免存在性返回类型,例如
object DataContext {
def apply(sId: Int, mId: Int)[A <: DBObject]: DataContext[A] = ...
// or separate methods returning DataContext[Dimension1Agg] etc
}
如果可能的话。