《programming in scala》2ed chap9学习笔记

import java.io.{PrintWriter, File}

/**
 * Created by ly on 13-12-27.
 */
object ControlAbstraction {

  object FileMatcher {
    // 9.1 Reducing code duplication
    private def filesHere = (new File(".")).listFiles

    def fileMatching(query: String, matcher: (String, String) => Boolean) = {
      for (file <- filesHere if matcher(file.getName, query))
      yield file
    }

    def fileEnding_Full(query: String) = fileMatching(query, (fileName: String, query: String) => fileName.endsWith(query))

    // 因为有类型推导,且每个参数按顺序只用了一遍,所以可以用_placeholder
    // 不是closure,因为matcher的两个参数都是bound variable,没有free
    def fileEnding(query: String) = fileMatching(query, _.endsWith(_))

    def fileContaining(query: String) = fileMatching(query, _.contains(_))

    def fileRegex(query: String) = fileMatching(query, _.matches(_))


    // 使用closure避免query参数的传递
    private def fileMatchingClosure(matcher: String => Boolean) = {
      for (file <- filesHere if matcher(file.getName)) yield file
    }

    def fileEndingClosure(query: String) = fileMatchingClosure(_.endsWith(query))

    /*
    9.2 Simplifying client code
    collections types special-purpose looping: List, Set, Map, exists, filter, map
     */

    /*
    9.3 Currying
    A curried function is applied to multiple argument lists, instead of just one.
     */
    def curriedSum(x: Int)(y: Int) = x + y

    def first(x: Int) = (y: Int) => x + y

    val second = first(1)
    val onePlus = curriedSum(1) _
    val result = onePlus(2) // 3

    /*
    9.4 Writing new control structures
    In languages with first-class functions, you can effectively make new control structures even though the syntax of the language is fixed. All you need to
do is create methods that take functions as arguments.
     */
    // 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)
    )
    /*
    One way in which you can make the client code look a bit more like a
built-in control structure is to use curly braces instead of parentheses to sur-
round the argument list. In any method invocation in Scala in which you’re
passing in exactly one argument, you can opt to use curly braces to surround
the argument instead of parentheses.
     */
    println("Hello, kitty!")
    println {
      "Hello, kitty"
    }

    // 但是两个参数不行,因此需要用curried函数
    //"Hello".substring{7, 9}
    def withPrintWriterCurried(file: File)(op: PrintWriter => Unit) {
      val writer = new PrintWriter(file)
      try {
        op(writer)
      } finally {
        writer.close()
      }
    }

    // 用{}更像是native control structure
    withPrintWriterCurried(new File("data.txt")) {
      writer => writer.println(new java.util.Date())
    }

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

    withPrintWriterCurried2 {
      writer => writer.println(new java.util.Date())
    }(new File("."))

    /*
    9.5 By-name parameters
    withPrintWriter第二个参数,还需要传递writer =>...如果不需要参数的话,可以写得更简洁
     */
    var assertionsEnabled = false

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

    myAssert(() => 5 > 3)

    //myAssert(5 > 3) // Won’t work, because missing () =>

    /*
     byNameAssert参数会在函数调用之后在evaluated,而boolAssert会在函数调用之前先evaluated
     By contrast, because the type of byNameAssert ’s
predicate parameter is => Boolean , the expression inside the parentheses
in byNameAssert(5 > 3) is not evaluated before the call to byNameAssert .
Instead a function value will be created whose apply method will evaluate
5 > 3 , and this function value will be passed to byNameAssert .
     */
    def byNameAssert(predicate: => Boolean) =
      if (assertionsEnabled && !predicate)
        throw new AssertionError

    byNameAssert(5 > 3)
    byNameAssert(1 / 0 == 0)

    // 没有问题

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

    boolAssert(5 > 3)
    boolAssert(1 / 0 == 0) // java.lang.ArithmeticException: / by zero
  }

  def main(args: Array[String]) {

  }

}


你可能感兴趣的:(scala)