美文网首页
functional scala no.1

functional scala no.1

作者: 来福马斯特 | 来源:发表于2017-09-18 21:34 被阅读8次

    通常我们作为java开发程序员转scala的时候,经常还是习惯性的用var这种命令式的方式来编码。其实scala里有更合适的函数编程
    下面的以一个打印文件内容的例子为例,看下两种方案的区别。
    这里主要看下widthOfLength的用法
    假如是java方式的写法

    def widthOfLength(s:String) = {
        var maxWidth = 0
        for (line <- lines)
        maxWidth = maxWidth.max(widthOfLength(line))
    }
    

    如果换成函数式,去除var的引用。

    def widthOfLength(s: String) = s.length.toString.length
    
    import scala.io.Source
    
    def widthOfLength(s: String) = s.length.toString.length
    
    if (args.length > 0) {
        val lines = Source.fromFile(args(0)).getLines().toList
        val longestLine = lines.reduceLeft(
            (a, b) => if (a.length > b.length) a else b
        )
        val maxWidth = widthOfLength(longestLine)
    }
    for (line <- lines) {
        val numSpaces = maxWidth - widthOfLength(line)
        val padding = " " * numSpaces
        println(padding + line.length + " | " + line)
    }else
    Console.err.println("Please enter filename")
    

    效果图

    22 | import scala.io.Source
     0 | 
    22 | if (args.length > 0) {
    51 | for (line <- Source.fromFile(args(0)).getLines())
    37 |   println(line.length + " " + line)
     1 | }
     4 | else
    46 |   Console.err.println("Please enter filename")
    

    以上就是最简单的函数式,去除var可变变量的依赖

    利用函数第一公民的特点

    定义一个叫做withPrintWriter的方法。用于解决Writer等资源close的问题。这种模式其实也叫作loan pattern。借贷模式,我把某个资源借给你用,你只要定义一个方法,我作为借贷方会提供你这个资源,并且我自己会确保在最后释放这个资源

    def withPrintWriter(file: File, op: PrintWriter => Unit) = {
        val writer = new PrintWriter(file)
        try {
            op(writer)
        } finally {
            writer.close()
        }
    }
    

    使用的时候,就可以直接这么写

    withPrintWriter(
        new File("date.txt"),
        writer => writer.println(new java.util.Date)
    )
    

    scala里为了更加美观的展示方法调用,当方法只有一个参数的时候,可以用花括号替代小括号
    例如

    println("Hello, world!")
    

    可以写成

    println { "Hello, world!" }
    

    但是如果是

    g.substring (7,9)
    

    却不可以写成:

    g.substring {7,9} //error
    

    但是我们可以使用“分居参数”函数啊,把上面的例子改造下

    def withPrintWriter(file: File)(op: PrintWriter => Unit) = {
        val writer = new PrintWriter(file)
        try {
            op(writer)
        } finally {
            writer.close()
        }
    }
    

    调用方就可以这么玩了!!!仿佛写了个方法

    val file = new File("date.txt")
    withPrintWriter(file) { writer =>
        writer.println(new java.util.Date)
    }
    

    引申出来,如果我设计了这么一个自定义的assert,叫做myAssert

    var assertionsEnabled = true
    def myAssert(predicate: () => Boolean) =
        if (assertionsEnabled && !predicate())
            throw new AssertionError
    

    我可以这么用

    myAssert(() => 5 > 3)
    

    就是有点别扭,于是,我们可以使用BY-NAME PARAMETERS 语法糖进一步简化
    修改定义为

    def byNameAssert(predicate: => Boolean) =
        if (assertionsEnabled && !predicate)
            throw new AssertionError
    

    嘿,我们调用的时候就可以省掉参数部分了

    byNameAssert(5 > 3)
    

    相关文章

      网友评论

          本文标题:functional scala no.1

          本文链接:https://www.haomeiwen.com/subject/ikqisxtx.html