Scala类型推断没有注意到这些类型是相同的,不管它们是什么
我这里有一个设计模式,其中有一个对象生成器(MorselGenerator及其子对象),其任何实例总是生成相同类型的对象(Morsel及其子对象),但类型检查器不允许我对两个或多个生成的对象执行任何操作,因为我相信它们可能不同 我如何通过类型检查器Scala类型推断没有注意到这些类型是相同的,不管它们是什么,scala,type-inference,abstract-type,static-polymorphism,dependent-type,Scala,Type Inference,Abstract Type,Static Polymorphism,Dependent Type,我这里有一个设计模式,其中有一个对象生成器(MorselGenerator及其子对象),其任何实例总是生成相同类型的对象(Morsel及其子对象),但类型检查器不允许我对两个或多个生成的对象执行任何操作,因为我相信它们可能不同 我如何通过类型检查器 trait Morsel { type M <: Morsel def calories : Float def + (v : M) : M } trait MorselGenerator { type Mg &
trait Morsel
{
type M <: Morsel
def calories : Float
def + (v : M) : M
}
trait MorselGenerator
{
type Mg <: Morsel
def generateMorsel : Mg
}
class HotDog(c : Float, l : Float, w : Float) extends Morsel
{
type M = HotDog
val calories : Float = c
val length : Float = l
val width : Float = w
def + (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width)
}
class HotDogGenerator extends MorselGenerator
{
type Mg = HotDog
def generateMorsel : HotDog = new HotDog(500.0f, 3.14159f, 445.1f)
}
object Factory
{
def main ( args : Array[String] )
{
val hdGen = new HotDogGenerator()
println(eatTwo(hdGen))
}
def eatTwo ( mGen : MorselGenerator )
{
val v0 : mGen.Mg = mGen.generateMorsel
val v1 : mGen.Mg = mGen.generateMorsel
v0 + v1 /// ERROR HERE
}
}
更新
这里是C++代码,它或多或少等价于我正在尝试做的事情。请注意,eatTwo函数是完全多态的,没有引用特定派生类型的Morsel或MorselGenerator
#include <stdlib.h>
#include <stdio.h>
template <class M> class Morsel
{
public:
Morsel(float c) : calories(c) {}
float calories;
virtual M operator + (const M& rhs) const = 0;
};
template <class M> class MorselGenerator
{
public:
virtual M * generateMorsel() const = 0;
};
class HotDog : public Morsel<HotDog>
{
public:
HotDog(float c, float l, float w) : Morsel<HotDog>(c), length(l), width(w) {}
float length, width;
HotDog operator + (const HotDog& rhs) const
{ return HotDog(calories+rhs.calories, length+rhs.length, width+rhs.width); }
};
class HotDogGenerator : public MorselGenerator<HotDog>
{
HotDog * generateMorsel() const { return new HotDog(500.0f, 3.14159f, 445.1f); }
};
///////////////////////////////////////////////
template <class MorselType> float eatTwo ( const MorselGenerator<MorselType>& mGen)
{
MorselType * m0 = mGen.generateMorsel();
MorselType * m1 = mGen.generateMorsel();
float sum = ((*m0) + (*m1)).calories;
delete m0; delete m1;
return sum;
}
int main()
{
MorselGenerator<HotDog> * morselStream = new HotDogGenerator();
printf("Calories Ingested: %.2f\n", eatTwo(*morselStream));
delete morselStream;
}
#包括
#包括
模板类小块
{
公众:
一小块(浮动c):卡路里(c){}
浮动卡路里;
虚拟M运算符+(常量M&rhs)常量=0;
};
模板类MorselGenerator
{
公众:
虚拟M*generateMorsel()常量=0;
};
班级热狗:公共小吃
{
公众:
热狗(浮点数c,浮点数l,浮点数w):小块(c),长度(l),宽度(w){}
浮动长度、宽度;
热狗操作员+(常数热狗和rhs)常数
{返回热狗(卡路里+rhs.Carries,长度+rhs.length,宽度+rhs.width);}
};
类别HotDogGenerator:公共MorselGenerator
{
HotDog*generateMorsel()常量{返回新的HotDog(500.0f,3.14159f,445.1f);}
};
///////////////////////////////////////////////
模板浮动EATwo(常量MorselGenerator和mGen)
{
morseType*m0=mGen.generateMorsel();
MorseType*m1=mGen.generateMorsel();
浮动总和=(*m0)+(*m1)).卡路里;
删除m0;删除m1;
回报金额;
}
int main()
{
MorselGenerator*morselStream=新的HotDogGenerator();
printf(“摄入的卡路里:%.2f\n”,eatTwo(*morselStream));
删除morselStream;
}
这就是Scala中成员类型的工作方式:只有当外部对象(编译器已知)相同时,才认为它们是相等的。一种选择是改用类型参数:
trait Morsel[M <: Morsel]
{
def calories : Float
def + (v : M) : M
}
trait MorselGenerator[Mg <: Morsel]
{
def generateMorsel : Mg
}
...
trait-Morsel[M这个错误是有意义的,因为在编译失败的方法中,编译器不能保证您没有向热狗中添加冰淇淋
HotDog中的+方法有助于突出问题,事实上,您没有覆盖该方法,而是添加了一个新方法:
def + (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width)
您明确需要添加的类型与“this”具有相同的类型
这样定义Morsel,问题就几乎解决了:
trait Morsel {
def calories : Float
def + (v : Morsel) : Morsel
}
最后一部分是正确覆盖+方法:
override def + (v : Morsel): Morsel = v match {
case hd: HotDog => new HotDog(hd.calories + calories, hd.length + length, hd.width + width)
case x => throw new IllegalArgumentException("eurgh!")
}
我不确定你是否可以让编译器使用你提供的格式的代码来阻止添加冰淇淋和热狗。一个可能的解决方案(我已经用添加替换+
,在这里远离+(字符串,字符串)
,最后,+
是可以的):
trait-Morsel[M///这就是诀窍
def卡路里:浮动
def添加(v:M):M
}
性状MorselGenerator[Mg和轻微的另一变异:
trait MorselGenerator {
type M <: Morsel
trait Morsel { this: M =>
def calories : Float
def add (v : M) : M
}
def generateMorsel : M
}
class HotDogGenerator extends MorselGenerator
{
type M = HotDog
class HotDog(c : Float, l : Float, w : Float) extends Morsel {
val calories : Float = c
val length : Float = l
val width : Float = w
def add (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width)
}
def generateMorsel: HotDog = new HotDog(500.0f, 3.14159f, 445.1f)
}
object Factory extends App
{
val hdGen = new HotDogGenerator()
hdGen.generateMorsel add hdGen.generateMorsel add hdGen.generateMorsel
produceDouble(hdGen)
def produceDouble(gen: MorselGenerator): MorselGenerator#Morsel = {
gen.generateMorsel add gen.generateMorsel
}
}
trait-MorselGenerator{
M型
def卡路里:浮动
def添加(v:M):M
}
def generateMorsel:M
}
类HotDogGenerator扩展了MorselGenerator
{
类型M=热狗
类热狗(c:Float,l:Float,w:Float)扩展一小块{
val卡路里:浮动=c
val长度:Float=l
val宽度:浮动=w
def add(v:HotDog):HotDog=新热狗(v.carries+carries,v.length+length,v.width+width)
}
def generateMorsel:HotDog=新热狗(500.0f、3.14159f、445.1f)
}
对象工厂扩展应用程序
{
val hdGen=新的HotDogGenerator()
hdGen.generateMorsel添加hdGen.generateMorsel添加hdGen.generateMorsel
双倍产量(hdGen)
def produceDouble(gen:MorselGenerator):MorselGenerator#Morsel={
gen.generateMorsel添加gen.generateMorsel
}
}
可能不太有用,但它可能会显示问题出在哪里。Scala有“路径依赖”类型,因此,obj1.Type和obj2.Type是不同的类型,即使obj1.Type==obj2.Type。实际上,这似乎不起作用。首先,我们必须这样定义特征:trait Morsel[Mg这比class Hotdog更为循环。。。{type M=HotDog…}
。请参阅以下内容:
trait Morsel[M <: Morsel[M]] { /// this
this: M => /// and this make the trick
def calories : Float
def add(v : M) : M
}
trait MorselGenerator[Mg <: Morsel[Mg]]
{
def generateMorsel : Mg
}
class HotDog(c : Float, l : Float, w : Float) extends Morsel[HotDog]
{
val calories : Float = c
val length : Float = l
val width : Float = w
override def add (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width)
}
class HotDogGenerator extends MorselGenerator[HotDog]
{
def generateMorsel : HotDog = new HotDog(500.0f, 3.14159f, 445.1f)
}
object Factory extends App
{
def eatTwo[M <: Morsel[M]](mGen : MorselGenerator[M]) = {
val v0 = mGen.generateMorsel
val v1 = mGen.generateMorsel
v0 add v1
}
val hdGen = new HotDogGenerator()
println(eatTwo(hdGen))
}
trait MorselGenerator {
type M <: Morsel
trait Morsel { this: M =>
def calories : Float
def add (v : M) : M
}
def generateMorsel : M
}
class HotDogGenerator extends MorselGenerator
{
type M = HotDog
class HotDog(c : Float, l : Float, w : Float) extends Morsel {
val calories : Float = c
val length : Float = l
val width : Float = w
def add (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width)
}
def generateMorsel: HotDog = new HotDog(500.0f, 3.14159f, 445.1f)
}
object Factory extends App
{
val hdGen = new HotDogGenerator()
hdGen.generateMorsel add hdGen.generateMorsel add hdGen.generateMorsel
produceDouble(hdGen)
def produceDouble(gen: MorselGenerator): MorselGenerator#Morsel = {
gen.generateMorsel add gen.generateMorsel
}
}