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

时间:2016-08-17 04:20:07

标签: scala currying type-parameter type-level-computation

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

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell cell.textLabel?.text = self.items[indexPath.row][0] cell.accessibilityLabel = self.items[indexPath.row][bigSort] cell.selectionStyle = .None for x in 0..<4 { let button = UIButton() let marginStart = w - tickWidthInCell * 4 - 9 + (tickWidthInCell + 2) * x let margin = CGFloat(marginStart) button.frame = CGRectMake(margin, CGFloat(cellHeightMargin), CGFloat(tickWidthInCell), CGFloat(tickHeightInCell)) button.layer.borderColor = GRAY.CGColor if (self.items[indexPath.row][1] == "Special" && x % 2 != 0) { button.backgroundColor = UIColor.clearColor() button.layer.borderColor = UIColor.clearColor().CGColor //button.hidden = true } else { button.addTarget(self, action: #selector(cellButtonClicked), forControlEvents: .TouchUpInside) button.backgroundColor = UIColor(netHex:0x222222) button.layer.borderWidth = 1 } cell.contentView.addSubview(button) } return cell }

但是,预期的用法是应该推断类型参数def foo[A, B, C](b: B, c: C)(implicit ev: Writer[A])B(基于传入的参数)。并且调用者应该只需要明确地指定C(例如,使编译器选择适当的隐式)。不幸的是,Scala只允许调用者指定所有类型参数或不允许任何类型参数。从某种意义上说,我希望咖喱的类型参数:

A

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

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

1 个答案:

答案 0 :(得分:5)

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

我在这里写过这篇文章 - https://nmap.org/nsedoc/scripts/http-wordpress-brute.html

对于您的具体示例,您需要在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和推断的类型签名,我想避免这两种情况。