为 A 和 B 类型创建 given 的最简单方法是什么?

What is the simplest way to create given for A & B type?

我有

trait Foo:
  def foo: Int

trait Bar:
  def bar: Int

given Foo with
  def foo = 1

given Bar with
  def bar = 1

我有一个函数foobar

type FooBar = Foo & Bar
def foobar(using FooBar) = ...

如果我已经给定 A 和给定 B

,为 A & B 类型创建给定的最简单方法是什么

诚然,我没有直接的 Scala 3 经验,但最简单的解决方案可以归结为:

given aAndB(using a: A, b: B): A & B with {
  def foo: Int = a.foo
  def bar: Int = b.bar
}

您有效地将 A 和 B 粘合在一起并适当地调度。

有可能实现一个自动调度(当没有冲突时)的宏。

A​​FAICT,这相当于 Scala 2:

implicit def aAndB(implicit a: A, b: B) = new A with B {
  def foo: Int = a.foo
  def bar: Int = b.bar
}

您可以通过在 given 实例中嵌套 using 子句来获得 Foo & Bar,但是一旦您开始修改 FooBar 中的值,结果可能不是您所期望的因为 FooBar 也是 FooBar 并且事情开始递归:

trait FooBar extends Foo with Bar

given (using f: Foo, b: Bar): FooBar with
  def foo = f.foo + 1
  def bar = b.bar + 2

def fooBar(using fb: Foo & Bar) = (fb.foo, fb.bar)
def foo(using f: Foo) = f.foo
def bar(using b: Bar) = b.bar

@main def main() =
  println(foo) //2
  println(bar) //3
  println(fooBar) //(3, 5)

IMO 你应该避免与类型类的子类型关系并定义 FooBar 而不扩展 FooBar:

trait FooBar:
  def foo: Int
  def bar: Int

given (using f: Foo, b: Bar): FooBar with
  def foo = f.foo + 1
  def bar = b.bar + 2

所以,在大家的帮助下,我认为最简单的解决方案是

given (using f: Foo, b: Bar): Foo with Bar with 
  export f.*
  export b.*