首页 文章

在Scala中,是否可以“定义”def的类型参数?

提问于
浏览
4

假设我有一个带有多个类型参数的def:

def foo[A, B, C](b: B, c: C)(implicit ev: Writer[A])

但是,预期用法是应推断类型参数 BC (基于传入的参数) . 调用者只需要明确指定 A (例如,编译器选择适当的隐式) . 不幸的是,Scala只允许调用者指定所有类型参数或不允许任何类型参数 . 从某种意义上说,我希望咖喱的类型参数:

def foo[A][B, C]...

在Scala中有一些技巧可以实现吗?

(如果我的具体例子没有完全合理,我很乐意通过建议改进它 . )

1 回答

  • 5

    我能够解决这个问题的最好方法是定义一个包含curried类型信息的类,然后使用 apply 方法来模拟函数调用 .

    我在这里写过这篇文章 - http://caryrobbins.com/dev/scala-type-curry/

    对于您的具体示例,您需要将 implicit ev: Writes[A] 放在 apply 的签名中,而不是 foo 的签名中 . 这是因为它导致显式传递隐式参数或隐式调用 apply 方法之间的歧义 .

    以下是您的示例的示例实现 -

    object Example {
      def foo[A]: _Foo[A] = _foo.asInstanceOf[_Foo[A]]
    
      final class _Foo[A] private[Example] {
        def apply[B, C](b: B, c: C)(implicit ev: Writes[A]): Unit = ???
      }
    
      private lazy val _foo = new _Foo[Nothing]
    }
    

    然后,您可以提供您希望咖喱的类型参数,并推断传递给 apply 方法的以下参数 .

    Example.foo[Int]("bar", new Object)
    

    如果最终需要指定其他类型参数,可以通过显式调用 apply 来实现;虽然,我从未见过有必要这样做 .

    Example.foo[Int].apply[String, Object]("bar", new Object)
    

    如果您不想使用中间类型,您也可以使用结构类型,我在上述帖子中讨论过;但是,这需要 reflectiveCalls 和推断类型签名,我想避免这两种签名 .

相关问题