当类型参数具有公共类型时,Scala添加扩展方法

Posted

技术标签:

【中文标题】当类型参数具有公共类型时,Scala添加扩展方法【英文标题】:Scala add extension method when the type params have a common type 【发布时间】:2022-01-01 01:52:36 【问题描述】:

我有一个类型 Foo[+A, +B] 和一个类型 Bar[+B]。我想像这样将扩展方法bar添加到Foo

implicit class FooSyntax[A](foo: Foo[A, Bar[A]]) 
   def bar: A = ???

所以扩展方法只适用于BBar[A]的情况。因此,以下所有内容都应该编译——

trait Fruit
trait Apple  extends Fruit
trait Banana extends Fruit
def foo0: Foo[Apple, Bar[Banana]] = ???
def foo1: Foo[Apple, Bar[String]] = ???
def foo2: Foo[Apple, Bar[Apple]]  = ???
def foo3: Foo[Apple, List[Apple]] = ???

foo0.bar // Fruit
foo1.bar // Object
foo2.bar // Apple

对于我的用例,我希望能够在没有 FooSyntax 的情况下使用隐式要求来执行此操作,这样该方法始终可用并且易于发现,但是只有在满足类型条件时才可以调用它.这就是我到目前为止所做的——

trait Foo[+A, +B] 
    def bar[C <: A](implicit evA: A <:< C, evB: B <:< Bar[C]): C

不用说,这是行不通的。

【问题讨论】:

我希望该方法始终可用以便更好地发现,但只有在满足条件时才可以调用它。 【参考方案1】:
trait Foo[+A, +B] 
  def bar(implicit ev: FooBar[A, B]): ev.Out


trait Bar[+B]

trait FooBar[-A, -B] 
  type Out


object FooBar 
  type Aux[A] = FooBar[A, Bar[A]]  type Out = A 

  implicit def x[A]: FooBar.Aux[A] =
    new FooBar[A, Bar[A]] 
      override type Out = A
    

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案2】:

您需要做的就是从C 中删除绑定的类型,并留下隐含的证据来完成它的工作。

trait Bar[+B]

trait Foo[+A, +B] 
  def bar[C](implicit ev1: A <:< C, ev: B <:< Bar[C]): C = ???

那么你可以这样做(如预期的那样)

foo0.bar // Fruit
foo1.bar // Object
foo2.bar // Apple

可以看到代码运行here

【讨论】:

为什么在scala 2.13.x 中不起作用? @JohnyTKoshy 啊,我的错。我忘了 Scastie 默认使用 Scala 3。嗯,类型推断算法在3.0.0中得到了改进,看来旧版本不能做你想做的了。 这不是我的问题。 OP 可能正在使用3.0.0。我在2.13.x 中尝试了同样的方法。无论如何,谢谢。 是的,我正在努力让它在 Scala 中工作 2.13.7

以上是关于当类型参数具有公共类型时,Scala添加扩展方法的主要内容,如果未能解决你的问题,请参考以下文章

在Fortran中,在扩展定义中,如何将公共过程设置为私有?

Scala之类型参数和对象

“T”必须是具有公共的无参数构造函数的非抽象类型,才能用作泛型类型或方法

Scala的泛型

Scala Class etc. 2

Scala隐式参数