【问题标题】:scala3 extension method type parameterscala3 扩展方法类型参数
【发布时间】:2021-03-16 00:34:21
【问题描述】:

这是我的 scala2 代码到 scala3 的直接翻译

trait Narrow[F[_], A, B <: A: ClassTag]:
  def apply(fa: F[A]): F[B]

extension [F[_], A] (fa: F[A]):
  def narrow[B: ClassTag] (using op: Narrow[F, A, B]): F[B] = op(fa)

我需要在调用站点指定窄操作的类型,但是扩展方法不允许该语法。对于这个限制有什么最好的解决方法?

这样做的目的是能够缩小集合/尝试/任何东西中的类型。窄类型类将对内部的任何内容进行平面映射,比较运行时类型,如果它匹配将 B 包装在 F 中,否则返回一个空 F

trait A
trait B extends A
object A extends A
object B extends B

val bb: List[B] = List(A, A, B, B, A)
  .narrow[B]
assert(bb == List(B, B))

【问题讨论】:

标签: scala extension-methods dotty scala-3


【解决方案1】:

如果你能处理丑陋,你可以使用多态函数:

extension [F[_], A] (fa: F[A]):
  def narrow() = [B <: A] => (using op: Narrow[F, A, B]) => op(fa)

然后您可以使用foo.narrow()[String] 调用它。 Here 在 Scastie。

narrow() 是必需的,因为没有它,类型参数将转到扩展而不是多态函数。

将来,Scala 3 可能允许将类型参数直接传递给扩展中的方法,但现在,您可以继续使用 Scala 2 隐式类并在下一个版本后更改它:

implicit class NarrowOps[F[_], A](fa: F[A]):
  def narrow[B <: A](using op: Narrow[F, A, B]) = op(fa)

Scastie

旁注:您的扩展程序中不再需要B: ClassTag,尽管我相信您确实需要使用绑定的B &lt;: A。

【讨论】:

  • 当然,我不需要 ClassTag,因为它是写的,但是一旦我尝试实现一个实际的 Narrow,那么我将需要它来进行运行时类型检查
  • 这是一个巧妙的技巧。肯定会把它放在我的工具箱里。
【解决方案2】:

我无法忍受呼叫站点上的()。我决定尝试使用仅带有类型参数的 apply 方法隐式转换为类型。

trait NarrowTypeClass[F[_], A, B <: A: ClassTag]:
  def apply(fa: F[A]): F[B]

given [F[_], A] as Conversion[F[A], Narrowable[F, A]] = Narrowable(_)

sealed class Narrowable [F[_], A] (fa: F[A]):
  def narrow[B <: A: ClassTag] (using op: NarrowTypeClass[F, A, B]): F[B] = op(fa)

这似乎可以解决问题

【讨论】:

    猜你喜欢
    • 2021-09-09
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多