控制抽象

所有的函数都可以被分成通用部分,以及非通用部分,这将导致代码存在大量的冗余。

代码1-1

object FileMatcher {
  private def filesHere = new java.io.File(".").listFiles()
  def fileEnding(query: String) =
    for (file <- filesHere; if file.getName.endsWith(query)) yield file
  def fileContains(query: String) =
    for (file <- filesHere; if file.getName.contains(query)) yield file
}

代码1-1中,fileEnding和fileContains两个方法,一个是查询以query结尾的,一个是查询包含query的,虽然功能不同,但代码大部分却相同,随着功能的增加,冗余的代码将会越来越多,维护也会越来越困难。为了解决这一问题,可以使用高阶函数,可以将函数当做对象传入另外一个函数,如代码1-2。

object FileMatcher {
  private def filesHere = new java.io.File(".").listFiles()
  def filesMatching(query: String, matcher: (String, String) => Boolean) =
    for (file <- filesHere; if matcher(file.getName, query)) yield file
  def filedEnding(query: String) = filesMatching(query, _.endsWith(_))
  def filedContaining(query: String) = filesMatching(query, _.contains(_))
}

filesMatching方法除了接收一个String对象的参数,还接收一个函数值对象,这个函数值对象接收两个String对象,经过一系列计算,最后得出的结果为Boolean类型,将filedEnding和filedContaining两个方法分别将_.endsWith(_)_.contains(_)作为对象传入filesMatching方法中,下划线是占位符,如果有不懂的同学可以去看上一篇函数与闭包,红色下划线代表第一个参数,蓝色下划线代表第二个参数,经过改造,可以发现代码的冗余少了很多。

实际上,我们的代码还可以更精简一点,如代码1-3。

代码1-3

object FileMatcher {
  private def filesHere = new java.io.File(".").listFiles()
  def filesMatching(query: String, matcher: (String) => Boolean) =
    for (file <- filesHere; if matcher(file.getName)) yield file
  def filedEnding(query: String) = filesMatching(query, _.endsWith(query))
  def filedContaining(query: String) = filesMatching(query, _.contains(query))
}

柯里化

  柯里化的函数被应用于多个参数列表,而不是仅仅一个,代码1-4展示的是未被柯里化的函数,它实现了对两个Int类型参数的加法

代码1-4

scala> def add(x: Int, y: Int) = x + y
add: (x: Int, y: Int)Int

scala> add(1, 2)
res0: Int = 3

相对的,代码1-5展示了柯里化后的同一个函数

代码1-5

scala> def add(x: Int)(y: Int) = x + y
add: (x: Int)(y: Int)Int

scala> add(1)(2)
res1: Int = 3

当add方法被调用时,实际上接连调用两个传统函数。第一个函数调用带单个的名为x的Int参数,并返回第二个函数的函数值。第二个函数带Int参数y,如代码1-6

代码1-6

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

scala> val second = first(1)
second: Int => Int = <function1>

scala> second(2)
res2: Int = 3

first和second函数只是柯里化过程的一个演示,它们并不直接连在add函数上,尽管如此,仍然有一个方式获得实际指向add第二个函数的参考,可以用部分应用表达式方式,把占位符标注用在add里,如代码1-7

代码1-7

scala> def add(x: Int)(y: Int) = x + y
add: (x: Int)(y: Int)Int

scala> add(1)(2)
res1: Int = 3

scala> val onePlus = add(1)_
onePlus: Int => Int = <function1>

scala> onePlus(2)
res3: Int = 3

scala> val twoPlus = add(2)_
twoPlus: Int => Int = <function1>

scala> twoPlus(3)
res4: Int = 5

add(1)_里的下划线是第二个参数列表的占位符,结果指向一个函数的参考,这个函数被调用的时候,对它唯一的Int参数加1并返回结果

双倍控制结构,能够重复一个操作两次,见代码1-8

代码1-8

scala> def twice(op: Double => Double, x: Double) = op(op(x))
twice: (op: Double => Double, x: Double)Double

scala> twice(_ + 1, 6)
res6: Double = 8.0

IO流的借贷模式,见代码1-9

代码1-9

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 Date))

使用这个方法的好处是,由withPrintWriter而并非用户代码,确认文件在结尾被关闭。因此忘记关闭文件是不可能的,之所以被称为借贷模式,因此控制抽象函数,如withPrintWriter,打开了资源并“贷出”给函数

传名参数

  传值参数在函数调用之前表达式会被求值,例如Int、Long等数值参数类型,而传名参数在函数调用前表达式不会求值,只会当做一个匿名参数传递下去,如代码1-10和代码1-11

代码1-10

scala> def strToIntByValue(s: String) = {
    println("call strToIntByValue")
    s.toInt
  }
strToIntByValue: (s: String)Int

scala> strToIntByValue({ println("hello world"); "10" })
hello world
call strToIntByValue
res0: Int = 10

代码1-10中,先打印了hello world再打印call strToIntByValue,方法strToIntByValue时已经对传入参数的表达式求值

代码1-11

scala> def strToIntByName(s: => String) = {
    println("call strToIntByName")
    s.toInt
  }
strToIntByName: (s: => String)Int

scala> strToIntByName({ println("hello world"); "10" })
call strToIntByName
hello world
res1: Int = 10

代码1-11,先打印了strToIntByName再打印hello world,在调用strToIntByName时并未对传入参数的表达式求值,一直到需要用到传入参数表达式的时候

时间: 2024-10-27 12:33:00

控制抽象的相关文章

Scala控制抽象

private def filesHere = (new java.io.File(".")).listFiles() def filesEnding(query: String) = for(file <- filesHere; if file.getName.endsWith(query)) yield file def filesContaining(query : String) = for(file <- filesHere; if file.getName.co

Java web自定义标签按钮级别权限控制完美诠释(jplogic 快速开发平台)

接下来跟大家聊聊JavaWeb中权限控制,往大的方向说可以聊聊整合应用系统中的权限控制.在聊权限控制之前先跟大家聊聊RBAC.那么什么是RBAC呢?RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联的,用户通过成为适当角色的成员而得到这些角色的权限.这就极大地简化了权限的管理.在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色.角色可依新的需求和系统的

结构化方法与面向对象方法

结构化方法 结构化方法是一种传统的软件开发方法,这种方法强调的是自顶向下.逐步求精.模块化设计.结构化编码的思想与要点.结构化软件开发方法可以说是最早的软件开发方法,同时也是到现今开发应用中比较普遍.比较成熟的软件开发方法,由结构化方法所引入的工程与结构化的思想对于软件的设计.开发与编写都有很大的影响. 结构化方法中自顶向下的思想将程序的设计分层,将程序的功能分解,程序变成了一种逐步向下,从概况到详细的过程.而结构化方法中的模块化设计将程序所需要的各种功能分解,将一个系统划分为若干个模块,每一个

程序员的Scala

C#程序员的Scala之路第九章(Scala的层级) 摘要: 1.Scala的类层级Scala里类的顶端是Any所有的类都继承Any类,Any包括以下几个通用方法:final def ==(that: Any): Boolean final def !=(that: Any): Boolean def equals(that: Any): Boolean de...阅读全文 posted @ 2015-03-30 10:15 qg 阅读(2) | 评论 (0) 编辑 C#程序员的Scala之路第

程序员必读书单

作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文地址:http://www.cnblogs.com/figure9/p/developer-reading-list.html 关于 本文把程序员所需掌握的关键知识总结为三大类19个关键概念,然后给出了掌握每个关键概念所需的入门书籍,必读书籍,以及延伸阅读.旨在成为最好最全面的程序员必读书单. 前言 Reading makes a full man; conference a ready man; and writing

结构化方法与面向对象方法的比较

结构化方法与面向对象方法的比较 引言 结构化方法(SD方法)是一种传统的软件开发方法,它是由结构化分析.结构化设计和结构化程序设计三部分有机组合而成的.它的基本思想:把一个复杂问题的求解过程分阶段进行,而且这种分解是自顶向下,逐层分解,使得每个阶段处理的问题都控制在人们容易理解和处理的范围内. 面向对象方法(Object-Oriented Method)是一种把面向对象的思想应用于软件开发过程中,指导开发活动的系统方法,简称OO (Object-Oriented)方法,是建立在"对象"

程序员必读书

前言 Reading makes a full man; conference a ready man; and writing an exact man. Francis Bacon 优秀的程序员应该具备两方面能力: 良好的程序设计能力: 掌握常用的数据结构和算法(例如链表,栈,堆,队列,排序和散列): 理解计算机科学的核心概念(例如计算机系统结构.操作系统.编译原理和计算机网络): 熟悉至少两门以上编程语言(例如C++,Java,C#,和Python): 专业的软件开发素养: 具备良好的编程

compiler

http://www.lingcc.com/2012/05/16/12048/ a list of compiler books — 汗牛充栋的编译器参考资料 Posted on 2012年5月16日 by Lingcc | 14 Replies 前不久,有位<编译点滴>网友询问编译器方向的参考资料.其实之前讨论过一些编译器相关的在线资料–<有写编译器的冲动?这些资料很重要>.这篇博文就来总结总结编译技术相关的各类图书资料,供各位参考.这个书列是结合本人所了解的内容整理出来的,限于

程序员必读书单(转)

作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://lucida.me/blog/developer-reading-list/ 关于 本文把程序员所需掌握的关键知识总结为三大类19个关键概念,然后给出了掌握每个关键概念所需的入门书籍,必读书籍,以及延伸阅读.旨在成为最好最全面的程序员必读书单. 前言 Reading makes a full man; conference a ready man; and writing an exact man.