我想尝试编写一个类型,其方法可以是同类的,并返回相同类型的值:
object SimpleTest {
trait Foo extends Product with Serializable {
type Self <: Foo
def bar: Self
}
case class X() extends Foo {
type Self = X
def bar = this
}
case class Y() extends Foo {
type Self = Y
def bar = this
}
trait TC[A]
implicit val tc: TC[Foo] = new TC[Foo] { }
def tester[A: TC](x: Seq[A]) = "foo"
// tester(Seq(X(), Y()))
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,注释掉的行调用tester失败并出现以下错误(Scala 2.10):
Error: could not find implicit value …Run Code Online (Sandbox Code Playgroud) StackOverflow 上经常会问到返回当前类型的问题。这是一个这样的例子。通常的答案似乎是F 有界多态性或类型类模式解决方案。奥德斯基在F-bound 多态性有用吗?
F-bounds 确实增加了显着的复杂性。我希望能够摆脱它们,并用更高级的子类型替换它们
而 tpolecat(链接帖子的作者)建议
更好的策略是使用类型类,它可以巧妙地解决问题,并且几乎没有担心的余地。事实上,在这些情况下完全放弃子类型多态是值得考虑的。
确定以下缺点的地方
F-bounded polymorphism 将一个类型参数化为它自己的子类型,这是一个比用户通常想要的更弱的约束,这是一种表达“我的类型”的方式,你无法通过子类型精确表达。然而类型类可以直接表达这个想法,所以这就是我教初学者的东西
我的问题是,根据上述建议,有人可以证明 F 有界多态性是有利的,还是我们应该指出类型类解决方案作为解决返回电流类型问题的规范答案?
类型参数的 F 绑定多态性
trait Semigroup[A <: Semigroup[A]] { this: A =>
def combine(that: A): A
}
final case class Foo(v: Int) extends Semigroup[Foo] {
override def combine(that: Foo): Foo = Foo(this.v + that.v)
}
final case class Bar(v: String) extends Semigroup[Bar] {
override def combine(that: Bar): Bar = Bar(this.v …Run Code Online (Sandbox Code Playgroud) 假设我有一个克隆派生类的基类:
class Base
{
public:
virtual Base * clone()
{
return new Base();
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
我有一组派生类,使用奇怪的重复模板模式实现:
template <class T>
class CRTP : public Base
{
public:
virtual T * clone()
{
return new T();
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
我试图从这个进一步得出这样的:
class Derived : public CRTP<Derived>
{
public:
// ...
};
Run Code Online (Sandbox Code Playgroud)
我得到编译错误的效果:
error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone'
Run Code Online (Sandbox Code Playgroud)
我意识到这可能是编译器在实例化CRTP时不完全知道Derived的继承树的结果.此外,用(Base*)替换返回类型(T*)也会编译.但是,我想知道是否存在保留上述语义的工作.
c++ templates visual-studio-2010 crtp f-bounded-polymorphism
经过几个例子后,我不得不说,我不明白F-Bounded多态带来了什么.
使用scala学校的示例(https://twitter.github.io/scala_school/advanced-types.html#fbounded)
他们解释说他们需要一些F-Bounded类型,以便子类可以返回子类型.所以他们做这样的事情:
trait Container[A <: Container[A]] extends Ordered[A]
class MyContainer extends Container[MyContainer] {
def compare(that: MyContainer) = 0
}
Run Code Online (Sandbox Code Playgroud)
但是当我可以使用这样的东西时,我看不出使用这种类型有什么好处:
trait Container[A] extends Ordered[A]
class MyContainer extends Container[MyContainer] {
def compare(other: MyContainer) = 0
}
Run Code Online (Sandbox Code Playgroud)
任何解释都非常欢迎
谢谢
我想将F有界多态转换为抽象类型成员.
trait FBoundedMovable[Self <: FBoundedMovable[Self]] {
def moveTo(pos: Vect2): Self
}
Run Code Online (Sandbox Code Playgroud)
至
trait Movable { self =>
type Self <: (Movable { type Self = self.Self })
def moveTo(pos: Vect2): Self
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.
让我们定义一个实例:
case class Ship(pos: Vect2) extends Movable {
type Self = Ship
def moveTo(pos: Vect2) = copy(pos = pos)
}
Run Code Online (Sandbox Code Playgroud)
并尝试使用它:
// [error] found : a.Self
// [error] required: A
def move[A <: Movable](a: A, to: Vect2): A = a.moveTo(to)
Run Code Online (Sandbox Code Playgroud)
F有界版本工作正常.
def moveF[A <: FBoundedMovable[A]](a: A, to: …
scala abstract-type parametric-polymorphism f-bounded-polymorphism
我不能在Scala中编写以下F-bounded多态.为什么?
trait X[T <: X[T]]
object Y extends X[Y]
Run Code Online (Sandbox Code Playgroud)
我怎样才能表达并编译?
我正在尝试实现一个在定位器服务后面抽象的日志系统(以本指南的风格),以便日志系统可以针对各种不同的日志记录情况进行子类化。我希望能够使用 printf 样式格式字符串而不是 <<,但这意味着支持可变数量的参数。可变参数模板可以轻松解决这个问题,但是它们不能是虚拟的,这意味着基本日志记录类不能是抽象的(作为接口)。
理想情况下,我需要的是某种方法让父方法不模板化,而只是接受参数包,并将其转发到正确的(模板化的)子方法。我主要看到两种实现此目的的方法,一种是使用 va_list ,它显然不安全、复杂,并且实际上并不意味着可以轻松地与可变参数模板交互;另一种是 CRTP,它可以工作,但意味着不能声明抽象的指针定位器对象中的基类而不知道子类类型,这违背了目的。
下面是假设虚拟模板是一个东西的示例代码:
class Logger
{
public:
template <typename ... Args>
virtual void print(char *filename, int line, std::string &&msg, Args&& ... args) = 0;
protected:
template <typename ... Args>
std::string format(char *filename, int line, std::string &msg, Args&& ... args)
{
std::string output = "%s at line %i: " + msg;
int size = std::snprintf(nullptr, 0, output.c_str());
// +1 for null termination
std::vector<char> buf(size + 1);
std::snprintf(&buf[0], buf.size(), output.c_str(), filename, line, args...);
return …Run Code Online (Sandbox Code Playgroud) 我有这些模型:
trait Vehicle[T <: Vehicle[T]] { def update(): T }
class Car extends Vehicle[Car] { def update() = new Car() }
class Bus extends Vehicle[Bus] { def update() = new Bus() }
Run Code Online (Sandbox Code Playgroud)
如果我获得了一个a Vehicle[Car]并且调用的实例update(),我会得到一个Car.由于Car扩展Vehicle[Car](或简单地说,Car 是一个 Vehicle [Car]),我可以安全地将结果的类型设置为Vehicle[Car]:
val car = new Car
val anotherCar = car.update()
val anotherCarAsVehicle: Vehicle[Car] = car.update() // works as expected
Run Code Online (Sandbox Code Playgroud)
但是,如果我想,比如说,将实例Car和Bus一起放入一个列表中,那么我必须将列表类型设置为Vehicle[_ <: Vehicle[_]](具有简单的列表Vehicle[_]并且update()在元素上调用会产生Any …
在讨论 F 有界多态性之前,我已经很难理解支撑它的结构了。
trait Container[A]
trait Contained extends Container[Contained]
Run Code Online (Sandbox Code Playgroud)
这种构造似乎是一个微不足道的面向对象的事情,因为它也存在于java中,已经让我有点困惑了。
问题是,当我看到这个时, trait Contained extends Container[Contained]我感觉就像是无限类型递归。
当我们定义类型 List 时,即使我们有Cons[A](a:A, tail:List[A]),我们也有case object Nil。所以递归可以以 Nil 结束。
但在这里,我不明白我们如何不处于无限递归中?以及为什么它有效。
有人可以帮我解答一下吗?或者是否有任何文档、博客或任何可以解释其工作原理或实现方式的内容。