【问题标题】:What's the point of generic type in foreach?foreach 中的泛型类型有什么意义?
【发布时间】:2012-12-30 20:44:18
【问题描述】:

我很好奇 - 在 Traversableforeach 方法的声明中泛型类型 U 的意义何在?

def foreach[U](f: A => U): Unit

既然Function1 的返回类型是协变的,为什么不能这样:

def foreach(f: A => Any): Unit

?

【问题讨论】:

  • 我没有时间想出一个例子,但我强烈怀疑它是让类型推断器在推断函数的返回类型时忽略foreach。但我不知道有什么情况会引起我的注意(即Any 不会导致相同的推断)。

标签: scala generics types foreach


【解决方案1】:

不是 Martin Odersky,我只能猜测 :-) 看着 foreach 的 Scaladoc,我看到了这个:

  /** Applies a function `f` to all elements of this $coll.
   *
   *  @param  f   the function that is applied for its side-effect to every element.
   *              The result of function `f` is discarded.
   *              
   *  @tparam  U  the type parameter describing the result of function `f`. 
   *              This result will always be ignored. Typically `U` is `Unit`,
   *              but this is not necessary.
   *
   *  @usecase def foreach(f: A => Unit): Unit
   */

所以f 的返回类型无关紧要,它的结果总是被丢弃。对我来说,这表明在这里使用泛型类型参数来标记返回类型只是一个文档的微妙之处,它说“返回类型可以是任何东西,真的任何东西,你喜欢”。而Any 的返回类型可能会向(某些)读者建议对此处适用的函数类型进行某种限制。

另一方面是 Scala 从一开始就非常有意识地设计为通用的。所以 - 对我来说 - 在这里使用泛型类型参数与语言的一般理念是一致的,而使用 Any - 尽管在技术上可用 - 绝对是一种非泛型方法,与语言的其余部分不一致.

【讨论】:

    【解决方案2】:

    也许允许您从Traversable 继承,并利用来自f: A => U 的返回值U

    trait TraversableWithHandler[+A, E <: Option[Throwable]] extends Traversable[A] {
      override def foreach[U](f: A => U): Unit
      def handleError(t: E) 
    }
    

    例如在jQuery中,从foreach内部返回false等价于break,任何不同的值都是continue

    用例

    breakable { 
      List(1,2,3).foreach(_ match { 
        case 1 => println("ok")
        case 2 => 
          println("Sort of, soft interrupt?")
          return false
        case 3 => break
      })
    }
    

    因为下一个代码(并行),永远不会中断(在这种情况下,stackless throwable 解决方案似乎并不理想?):

    import scala.util.control.Breaks._
    
    breakable { 
      (0 to 100).toList.par.foreach(_ match { 
        case n if (n <= 50) => 
          println("#" * 100)
          try { break } catch { 
            case t: Throwable => println("" + t); break 
          }
        case n if (n > 50) => 
          println("" + n)
        case _ => "ok" 
      }) 
    }
    

    【讨论】:

    • -1:考虑到在这种情况下无堆栈异常无论如何都用于控制流,并且在这种情况下具有正式的返回值是没有用的,这是高度 不太可能。另外,您实际上并没有展示任何用例。我不知道如何使用上面的签名。
    • 这将与 Scaladoc 形成对比:“函数f 的结果被丢弃。”
    • 这个答案不仅是错误的,而且可能非常令人困惑。您刚刚重命名了类型参数,使其覆盖scala.Boolean——您肯定没有以某种方式限制Traversable 中声明的方法。
    • 你不能用 [U] 返回值做任何你不能用 Any 做的事情,并且调用 foreach 的东西实际上并没有将函数应用于每个元素该系列充其量只是要求混淆。
    • 仍然有隐藏错误,这次是E,如果你不隐藏E,你就没有遵守@987654340的里氏替换原则@通过限制它可以使用的函数类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    相关资源
    最近更新 更多