【问题标题】:Optional function parameter with generic return type具有通用返回类型的可选函数参数
【发布时间】:2010-07-13 15:14:43
【问题描述】:

您将如何实现通过正则表达式解析某些输入并将已建立的字符串转换为其他类型的类?我的做法是:

class ARegex[T](regex:Regex, reform:Option[String => T]){
  def findFirst(input:String):Option[T] = {
    (regex.findFirstIn(input), reform) match{
      case (None, _) => None
      case (Some(s), None) => Some(s) // this won't compile because of type mismatch
      case (Some(s), Some(fun)) => Some(fun(s))
    }
  }
}

class BRegex[T](regex:Regex, reform:Option[String => T]) {
  def findFirst(input:String) = {  //returns Option[Any] - erasure
    (regex.findFirstIn(input), reform) match{
      case (None, _) => None
      case (Some(s), None) => Some(s)
      case (Some(s), Some(fun)) => Some(fun(s))
    }
  }
}

【问题讨论】:

  • T 可以是任何东西。 TString 的唯一常见超类型是 Any。如果你有时想返回Some[String],有时想返回Some[T](或None),那么Option[Any]findFirst的返回类型最多可以说。

标签: scala types


【解决方案1】:

我们可以通过消除reform 的类型中的Option 部分来解决这个问题,并使用不同的机制来表明我们不想以任何方式更改匹配。这个机制是使用identity作为默认参数或者当你不想改变类型时传递标识。

class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){
  def findFirst(input:String):Option[T] = {
    regex.findFirstIn(input) match{
      case None => None
      case Some(s) => Some(reform(s))
    }
  }
}

new ARegex("something".r).findFirst("something else") //returns Option[String]
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int]

【讨论】:

  • 哦,我喜欢这个!我没有想到将身份用作默认参数。
  • 您可以将findFirst 的正文重写为regex findFirstIn input map reform。它真的会展示 Scala 的优雅。
  • @Daniel,这可能是最惯用的写法。我没有那样做(实际上,我做了但恢复了它......检查编辑历史记录)因为我觉得如果我与原来的偏差太大,它可能会掩盖我的答案的重要部分。
【解决方案2】:

嗯,问题类型不匹配,因为您返回的是StringT,当然,它们统一为Any。你不能说你要返回Option[T],然后返回Option[String]

除此之外,该代码的简化版本如下:

class ARegex[T](regex: Regex, reform: Option[String => T]) {
  def findFirst(input: String): Option[Any] =
    regex findFirstIn input map { s => reform map (_(s)) getOrElse s }
}

不过,您可以返回 Option[Either[String, T]]。代码如下所示:

class ARegex[T](regex: Regex, reform: Option[String => T]) {
  def findFirst(input: String): Option[Either[String, T]] =
    regex findFirstIn input map { s => reform map (_(s)) toRight s }
}

【讨论】:

    【解决方案3】:

    为什么要改革 Option[String => T] 而不是 String => T?如果您没有传入用于创建所需类型的实例的机制,则运行时系统没有任何机制可以实际创建适当的对象。如果你真的需要传入一个 Option[String => T] 那么你的第二种情况应该简单地返回 None。

    另外,flatMap 是你的朋友,它会给你正确的行为(即如果reform 为None,则该方法返回None。

    class RegexExtractor[T](regex: Regex, reform: Option[String => T]) {
      def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f))
    }
    

    【讨论】:

    • 如果reformNone,我不认为findFirst 的正确行为是返回None。他正在寻找一种方法来省略 reform 函数并让 findFirst 在这种情况下跳过转换。
    猜你喜欢
    • 1970-01-01
    • 2015-12-28
    • 2017-11-07
    • 1970-01-01
    • 2022-11-05
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    相关资源
    最近更新 更多