代码之家  ›  专栏  ›  技术社区  ›  sharath chandra

Scala函数文本类型问题

  •  0
  • sharath chandra  · 技术社区  · 8 年前

    为什么? executeCommand 正在接受 callBack 返回类型错误的函数?

    import scala.sys.process._
    
    object Test {
    
      def executeCommand(x: String)(y: Int => Unit) = {
        def matchStrToInt(str: String) = {
          str match {
            case "true"  => 1
            case "false" => 2
          }
        }
        y(matchStrToInt(x))
      }                                     //> executeCommand: (x: String)(y: Int => Unit)Unit
    
      executeCommand("true")(callBack)
    
      def callBack(x: Int): Int = {
        x
      }                                     //> callBack: (x: Int)Int
    
    }
    

    据我所知,Scala是一种严格的静态类型语言。 有人能解释一下背后的原因吗?

    1 回复  |  直到 8 年前
        1
  •  4
  •   Jasper-M    8 年前

    我认为这里发生的是Scala编译器中的两个独立机制在一起工作:

    价值抛弃

    这基本上只是一种避免显式写入的方法 () 这个 Unit 单元 是预期的类型。就像在 while 循环,a 单元 返回方法,a for(a <- list){ ... } 表达等。

    def foo: Unit = 42
    

    def foo: Unit = { 42; () }
    

    Eta扩展

    这就是 方法 在Scala中,转换为 功能 scala.FunctionN 班可以将函数作为值传递(因为它们是值),但不能将方法作为值传递。

    因此,编译器基本上执行以下转换:

    def foo(i: Int): Int = i
    def bar(f: Int => Int) = f
    
    bar(foo)
     ~~~>
    bar( (x1: Int) => foo(x1) )
    

    把两者结合起来

    所以当你有了这个代码:

    def foo(i: Int): Int = i
    def bar(f: Int => Unit) = f
    
    bar(foo)
    

    编译器将首先使用eta扩展进行转换 foo

    bar( (x1: Int) => foo(x1) )
    

    然后它会看到 foo(x1) 是类型的表达式 Int 而类型的表达式 单元 预计在那里。因此它将应用值丢弃。

    bar( (x1: Int) => { foo(x1); () } )
    

    您可以检查此“问题”仅在将方法转换为函数时发生:

    scala> def bar(f: Int => Unit) = f
    bar: (f: Int => Unit)Int => Unit
    
    scala> val foo = (i: Int) => i
    foo: Int => Int = <function1>
    
    scala> bar(foo)
    <console>:14: error: type mismatch;
     found   : Int => Int
     required: Int => Unit
           bar(foo)
               ^