加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

斯卡拉.有没有办法选择自我类型的超级方法实现?

发布时间:2020-12-16 10:01:06 所属栏目:安全 来源:网络整理
导读:当我扩展特征时,我可以选择使用哪种方法实现.像这儿: 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" } trai
当我扩展特征时,我可以选择使用哪种方法实现.像这儿:

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
  }

}

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

更新:
为什么我首先需要?我正在玩依赖注入使用自我类型而不是构造函数注入.所以我有一个基本特征转换器和子特征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)
    }
  }

}

我认为这是因为泛型,但它转变为不是.所以我只是想知道是否有可能以某种方式调用自我类型所选特征的超级方法.因为简单的继承是可能的.至于我原来的问题,我可以这样写,它会起作用:

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]这样的广泛抽象.

解决方法

从已经构造的类型调用超级方法是不可能的(你只能从内部完成).在您的示例中,您尝试在运行时构造的实例self上调用foo,因此foo是虚拟的并且可以被覆盖 – 编译器不知道将调用哪个实际实现(正式与实际类型问题) ).从技术上讲 – 不可能做你想做的事情(把虚拟方法称为静态方法).

天真的黑客是:

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

class C {
  self: CC =>

}

它基本上提供了你想要的封装 – 你可能想重新定义C类中的a和b,因为它们不可用(在C类本身中)直到你将C与CC混合.

请注意,在您提供的每个示例中(包括我的天真解决方案) – 结果val c无论如何都可以访问foo,并且将调用哪个foo取决于您如何混合A和B(A与B或B与A混合).所以,你得到的唯一封装是C类本身不会有foo方法.这意味着自我类型为您提供了一种临时关闭(私有)“子类”中的方法而不违反LSP的方法 – 但这不是唯一的方法(见下文).

除了所有这些,你试图实施的蛋糕注入被认为是不实用的authors.你可能想看看Thin Cake Pattern – 作为一个评论,我在实际项目中成功使用了这样的东西(与构造函数结合使用)注射).

我会这样实现你的转换器服务:

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 =>字符串,所以实际上你不需要单独的接口:

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

您可以使用对象对象转换器{…};如果您愿意,可以使用对象客户端{…}代替包.

这种封装甚至比基于自我类型的封装更强大,因为你无法从App对象访问fooConverter / barConverter(在你的例子中,foo仍然可以从val c = new C访问,其中A带有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
                     ^

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读