Scala 下划线

    技术2024-08-09  74

    Scala 下划线_ 简化匿名函数注意事项

    eta-expansion 概念

    把 x => func(x) 简化为 func _ 或 func 的过程称为 eta-conversion把 func 或 func _ 展开为 x => func(x) 的过程为 eta-expansion

    Eta Expansion 的就近expand 解析原则 Underscores extend outwards to the closest closing Expr: top-level expressions or expressions in parentheses 翻译:下划线_ 组成的表达式遇到括号() 或者最顶层表示它就会发生函数的扩展eta-expansion

    重点1:下划线组成的表达式,如果仅有下划线_ 不算是表达式重点2:下划线表达式遇到括号() 就会发生eta-expansion

    多个括号嵌套时不要用_ 简写

    # 使用scala REPL 演示 scala << 'EOF' // 错误写法 List(1, 2, 3).map((_*2)+1) // _*2 属于下划线表达式,遇到括号它就会转化为(x)=>{x*2} // ((_*2)+1) 就变成了((x)=>{x*2} + 1)// 一个匿名函数+1,结果不知道是什么东西自然报错 // 正确写法 List(1, 2, 3).map(_*2+1) // (_*2+1) 转化为(x)=>{x*2+1} // 正常的匿名函数,函数参数类型根据List 元素推断为Int // 建议使用正常的匿名函数写法,避免简写解析错误 List(1, 2, 3).map(x=>{x*2+1}) // 另外,单个_ 不构成表达式,以下写法都是正确的,且效果一样 List(1, 2, 3).map(_+1) List(1, 2, 3).map((_)+1) // 但是_.toString 就属于表达式了 List(1, 2, 3).foreach(println(_)) // 正常 List(1, 2, 3).foreach(println(_.toString)) // 报错 // 原因同上,下划线表达式(_.toString) 转化成了x=>x.toString 匿名函数 // 而println 只接收String 类型的参数,所以运行报错 // 退出scala REPL :quit EOF

    参数类型不确定时不能用_ 简写

    # 使用scala REPL 演示 scala << 'EOF' // 定义高阶函数(普通函数作为其参数) def ff(f: => Unit) { } // 错误传入函数 ff(_ + 1) // 报错 // 下划线表达式(_ + 1) 会被转化成((x) => {x + 1}) // x 的数据类型无法推断导致报错,这和集合的map 方法不同 // map 会根据集合元素推断作为参数的匿名函数的参数类型 List(1, 2, 3).map(_ + 1) // 正常 // 正确传入函数 ff((x: Int) => {x + 1}) // 正常 // 明确作为参数的匿名函数的参数类型 // 实际上,ff 定义时忽略了参数函数的参数类型 // 即ff 可以接收没有参数的代码块{} // 但代码块也是明确告诉高阶函数参数函数没有参数 ff({ }) // 正常 // 只要是明确指出,无论有没有参数都可以正常运行 // 退出scala REPL :quit EOF

    参考资料

    scala 下划线解析报错 scala eta-expansion

    Processed: 0.013, SQL: 10