gpt4 book ai didi

斯卡拉。有没有办法选择具有 self 类型的 super 方法实现?

转载 作者:行者123 更新时间:2023-12-01 01:56:39 25 4
gpt4 key购买 nike

当我扩展特征时,我可以选择使用哪种方法实现。像这儿:

object Main {

def main(args: Array[String]): Unit = {
val c = new C
println(c.a)
println(c.b)
}

trait Parent {
def foo: String
}

trait A extends Parent {
override def foo = "from A"
}

trait B extends Parent {
override def foo = "from B"
}

class C extends A with B {
val b = super[A].foo
val a = super[B].foo
}

}

但是,如果我想对自我类型做同样的事情,这似乎是不可能的:
object Main {

def main(args: Array[String]): Unit = {
val c = new C with A with B
println(c.a)
println(c.b)
}

trait Parent {
def foo: String
}

trait A extends Parent {
override def foo = "from A"
}

trait B extends Parent {
override def foo = "from B"
}

class C {
self: A with B =>

val b = super[A].foo
val a = super[B].foo
}

}

这不编译。我是对的,这是不可能的吗?如果我是对的,为什么会这样,是否有解决方法?

更新:
为什么我首先需要?我正在使用自类型而不是构造函数注入(inject)来玩依赖注入(inject)。所以我有一个基本特征转换器和子特征 FooConverter 和 BarConverter。我想这样写(当然行不通):
object Main {

class Foo

class Bar

trait Converter[A] {
def convert(a: A): String
}

trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}

trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}

class Service {

this: Converter[Foo] with Converter[Bar] =>

def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}

}

我认为这是因为泛型,但事实证明不是。所以我只是想知道是否有可能以某种方式调用具有自我类型的所选特征的 super 方法。因为通过简单的继承是可能的。至于我原来的问题,我可以这样写,它会起作用:
object Main {

class Foo

class Bar

trait Converter[A] {
def convert(a: A): String
}

trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}

trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}

class Service {

this: FooConverter with BarConverter =>

def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}

}

可能是更严格的抽象,但我不确定这对这种情况是否有害,以及我是否需要像 Converter[A] 这样广泛的抽象。

最佳答案

调用super已经构造类型的方法是不可能的(您只能从内部进行)。在您的示例中,您尝试调用 foo在实例上 self ,它是在运行时构造的,所以 foo是虚拟的并且可以被覆盖 - 编译器不知道将调用哪个实际实现(形式与真实类型问题)。所以从技术上讲 - 做你想做的事是不可能的(将虚拟方法称为静态方法)。

天真的黑客是:

trait CC extends A with B {
val b = super[A].foo
val a = super[B].foo
}

class C {
self: CC =>

}

它基本上提供了你想要的封装——你可能想重新定义 ab在 C 类中,因为在您混合 C 之前,它们将不可用(类型为 C 本身)与 CC .

请注意,在您提供的每个示例中(包括我的幼稚解决方案) - 结果 val c可以访问 foo无论如何,确切的 foo将被调用取决于你如何混合 AB ( A with BB with A )。所以,你得到的唯一封装是类型 C本身不会有 foo方法。这意味着 self-type 为您提供了一种在不违反 LSP 的情况下临时关闭(私有(private))“子类”中的方法的方法。 - 但这不是唯一的方法(见下文)。

除此之外,您尝试实现的蛋糕注入(inject)被一些人认为是不切实际的 authors .您可能想看看 Thin Cake Pattern - 作为评论,我在实际项目中成功使用了这样的东西(结合构造函数注入(inject))。

我会以这种方式实现您的转换器服务:
class Foo

class Bar

trait Converter[A] {
def convert(a: A): String
}

object FooConverter1 extends Converter[Foo] {
override def convert(a: Foo): String = ???
}

object BarConverter1 extends Converter[Bar] {
override def convert(a: Bar): String = ???
}


trait FooBarConvertService {
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]

def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)

}

}

trait Converters {
def fooConverter: Converter[Foo] = FooConverter1
def barConverter: Converter[Bar] = BarConverter1
}

object App extends FooBarConvertService with Converters with ...

这允许您在将它们放在一起时更改/模拟转换器实现。

我还注意到 Converter[Bar]只不过是 Function1[Bar, String]或只是 Bar => String ,所以实际上你不需要单独的接口(interface):
sealed trait FooBar //introduced it just to make types stronger, you can omit it if you prefer
class Foo extends FooBar
class Bar extends FooBar

trait FooBarConvertService {

type Converter[T <: FooBar] = T => String

def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}

}

trait FooConverterProvider {
def fooConverter: Foo => String = ???
}

trait BarConverterProvider {
def barConverter: Bar => String = ???
}

object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider

您也可以使用 def fooConverter(f: Foo): String = ???而是 def fooConverter: Foo => String = ??? .

谈论封装——这里比较弱,因为你可以访问传递依赖,所以如果你真的需要它——使用 private[package]修饰符。

转换器模块:
package converters

trait FooBarConvertService {

type Converter[T <: FooBar] = T => String

private[converters] def fooConverter: Converter[Foo]
private[converters] def barConverter: Converter[Bar]

def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}

}

trait FooConverterProvider {
private[converters] def fooConverter: Foo => String = ???
}

trait BarConverterProvider {
private[converters] def barConverter: Bar => String = ???
}

核心模块:
package client 
import converters._

object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider

您可以使用对象 object converters {...}; object client {...}如果你愿意,而不是包。

这种封装比基于自我类型的封装更强大,因为您无法访问 fooConverter/ barConverter来自 App对象(在您的示例中 foo 仍然可以从 val c = new C with A with B 访问):
 client.App.fooBar(new Foo, new Bar) //OK
client.App.fooConverter
<console>:13: error: method fooConverter in trait FooConverterProvider cannot be accessed in object client.App
client.App.fooConverter
^

关于斯卡拉。有没有办法选择具有 self 类型的 super 方法实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40024521/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com