Spark记录-Scala函数与闭包
函数声明
Scala函数声明具有以下形式 -
def functionName ([list of parameters]) : [return type]
如果不使用等号和方法体,则隐式声明抽象(abstract
)方法。
函数定义
Scala函数定义具有以下形式 -
语法
def functionName ([list of parameters]) : [return type] = {
function body
return [expr]
}
这里,返回类型可以是任何有效的Scala数据类型,参数列表将是由逗号分隔的变量列表,参数列表和返回类型是可选的。与Java非常相似,返回语句可以与表达式一起使用,以防函数返回值。 以下是将两个整数相加并返回其总和的函数,
语法
object add {
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
一个不返回任何东西的函数可以返回一个类似在Java中的void
类型,并表示该函数不返回任何内容。 在Scala中不返回任何东西的函数称为过程。
语法
object Hello{
def printMe( ) : Unit = {
println("Hello, Scala!")
}
}
调用函数
Scala为调用方法提供了许多句法变体。以下是调用方法的标准方法 -
functionName( list of parameters )
如果使用对象的实例调用函数,那么可使用与Java类似的点符号,如下所示:
[instance.]functionName( list of parameters )
尝试以下示例程序来定义并调用相同的函数 -
示例 -
object Demo {
def main(args: Array[String]) {
println( "Returned Value : " + addInt(5,7) );
}
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
将上述程序保存在源文件:Demo.scala中,使用以下命令编译和执行此程序。
Scala函数是Scala编程的核心,因此Scala被认为是函数式编程语言。以下是与Scala函数相关的几个重要概念,Scala程序员应该要理解。
Scala按名称调用函数
object Demo {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("Getting time in nano seconds")
System.nanoTime
}
def delayed( t: => Long ) = {
println("In delayed method")
println("Param: " + t)
}
}
Scala命名参数的函数
在正常的函数调用中,调用的参数按照被调用函数定义的参数顺序逐个匹配。命名参数允许您以不同的顺序将参数传递给函数。语法只是每个参数前面都有一个参数名称和一个等号。
尝试以下程序,它是一个简单的例子来显示具有命名参数的函数。
object Demo {
def main(args: Array[String]) {
printInt(b = 5, a = 7);
}
def printInt( a:Int, b:Int ) = {
println("Value of a : " + a );
println("Value of b : " + b );
}
}
将上述程序保存在源文件:Demo.scala中,使用以下命令编译和执行此程序。
Scala可变参数的函数
Scala允许指定函数的最后一个参数可重复。 这允许客户端将可变长度参数列表传递给函数。 这里,打印字符串函数里面的args
类型,被声明为类型String *
,实际上是Array [String]
。
尝试以下程序,这是一个简单的例子来演示如何使用带有可变参数的函数。
object Demo {
def main(args: Array[String]) {
printStrings("Hello", "Scala", "Python");
}
def printStrings( args:String* ) = {
var i : Int = 0;
for( arg <- args ){
println("Arg value[" + i + "] = " + arg );
i = i + 1;
}
}
}
Scala递归函数
递归在纯功能编程中起着重要作用,Scala支持递归函数。 递归表示一个函数可以重复调用自身。
尝试以下程序,它是一个很好的递归示例,它计算给定参数(数字)的阶乘。
示例
object Demo {
def main(args: Array[String]) {
for (i <- 1 to 10)
println( "Factorial of " + i + ": = " + factorial(i) )
}
def factorial(n: BigInt): BigInt = {
if (n <= 1)
1
else
n * factorial(n - 1)
}
}
Scala递归函数
Scala允许您指定函数参数的默认值。 这样一个参数可以从函数调用中选择性地省略,在这种情况下,相应的参数值将使用默认值。如果指定其中一个参数,则使用该参数将传递第一个参数,第二个参数将从默认值中获取。
尝试以下示例,它是为函数指定默认参数的示例 -
示例
object Demo {
def main(args: Array[String]) {
println( "Returned Value : " + addInt() );
}
def addInt( a:Int = 5, b:Int = 7 ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
Scala高阶函数
Scala允许定义高阶函数。它是将其他函数作为参数或其结果是函数的函数。
尝试以下示例程序,apply()
函数接受另一个函数f
和值v
,并将函数f
应用于v
。
示例
object Demo {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
Scala嵌套函数
Scala允许您定义函数内部的函数,而在其他函数中定义的函数称为局部函数。这是一个阶乘计算器的实现,我们使用传统的技术来调用第二个嵌套方法来完成工作。
尝试以下程序来了解如何实现嵌套函数。
示例
object Demo {
def main(args: Array[String]) {
println( factorial(0) )
println( factorial(1) )
println( factorial(2) )
println( factorial(3) )
}
def factorial(i: Int): Int = {
def fact(i: Int, accumulator: Int): Int = {
if (i <= 1)
accumulator
else
fact(i - 1, i * accumulator)
}
fact(i, 1)
}
}
Scala匿名函数
Scala提供了一个相对轻量级的语法来定义匿名函数。源代码中的匿名函数称为函数文字,在运行时,函数文字被实例化为称为函数值的对象。
Scala支持一级函数,函数可以用函数文字语法表达,即(x:Int)=> x + 1
,该函数可以由一个叫作函数值的对象来表示。
尝试以下表达式,它为整数创建一个后继函数 -
var inc = (x:Int) => x+1
变量inc
现在是一种可以像函数那样使用的函数 -
var x = inc(7)-1
还可以如下定义具有多个参数的函数:
var mul = (x: Int, y: Int) => x*y
变量mul
现在是可以像函数那样使用的函数 -
println(mul(3, 4))
也可以定义不带参数的函数,如下所示:
var userDir = () => { System.getProperty("user.dir") }
变量userDir
现在是可以像函数那样使用的函数 -
println( userDir )
Scala部分应用函数
当在调用一个函数时,把这个函数应用到参数中。 如果您传递所有预期的参数,则表示您已完全应用它。 如果只传递几个参数并不是全部参数,那么将返回部分应用的函数。这样就可以方便地绑定一些参数,其余的参数可稍后填写补上。
尝试以下,下面是一个简单的示例程序用来演示如何使用部分应用函数 -
import java.util.Date
object Demo {
def main(args: Array[String]) {
val date = new Date
log(date, "message1" )
Thread.sleep(1000)
log(date, "message2" )
Thread.sleep(1000)
log(date, "message3" )
}
def log(date: Date, message: String) = {
println(date + "----" + message)
}
}
将上述程序保存在源文件:Demo.scala 中,使用以下命令编译和执行此程序。
D:/> scalac Demo.scala
D:/> scala Demo
Mon Dec 02 12:52:41 CST 2018----message1
Mon Dec 02 12:52:41 CST 2018----message2
Mon Dec 02 12:52:41 CST 2018----message3
这里,log()
方法有两个参数:date
和message
。 我们想要多次调用该方法,具有相同的日期值,但不同的消息值。可以通过将参数部分地应用到log()
方法来消除将日期传递给每个调用的干扰。为此,首先将值绑定到date
参数,并将第二个参数绑定到其位置。 结果是存储在变量中的部分应用函数。
尝试以下示例程序以仅使用未绑定的参数消息来调用此新方法。
import java.util.Date
object Demo {
def main(args: Array[String]) {
val date = new Date
val logWithDateBound = log(date, _ : String)
logWithDateBound("message1" )
Thread.sleep(1000)
logWithDateBound("message2" )
Thread.sleep(1000)
logWithDateBound("message3" )
}
def log(date: Date, message: String) = {
println(date + "----" + message)
}
}
将上述程序保存在源文件:Demo.scala中,使用以下命令来编译和执行此程序。
D:\>scalac Demo.scala
D:\>scala Demo
Mon Dec 02 12:53:56 CST 2018----message1
Mon Dec 02 12:53:56 CST 2018----message2
Mon Dec 02 12:53:56 CST 2018----message3
Scala柯里化函数
柯里化(Currying)函数是一个带有多个参数,并引入到一个函数链中的函数,每个函数都使用一个参数。 柯里化(Currying)函数用多个参数表定义,如下所示:
def strcat(s1: String)(s2: String) = s1 + s2
或者,还可以使用以下语法定义柯里化(Currying)函数 -
def strcat(s1: String) = (s2: String) => s1 + s2
以下是调用柯里化(Currying)函数的语法 -
strcat("foo")("bar")
您可以根据需要在柯里化(Currying)函数上定义两个以上的参数。尝试下面一个简单的示例程序用来了解如何使用柯里化(Currying)函数 -
object Demo {
def main(args: Array[String]) {
val str1:String = "Hello, "
val str2:String = "Scala!"
println( "str1 + str2 = " + strcat(str1)(str2) )
}
def strcat(s1: String)(s2: String) = {
s1 + s2
}
}
将上述程序保存在源文件:Demo.scala 中,使用以下命令编译和执行此程序。
D:\> scalac Demo.scala
D:\> scala Demo
str1 + str2 = Hello, Scala!
Scala闭包
闭包是一个函数,它返回值取决于在此函数之外声明的一个或多个变量的值。
以下代码是一个匿名函数。
val multiplier = (i:Int) => i * 10
这里,函数体i * 10
中使用的唯一变量是i
,它被定义为该函数的一个参数。尝试以下代码 -
val multiplier = (i:Int) => i * factor
乘数有两个自由变量:i
和factor
。i
是函数的一个正式参数。 因此,每当调用乘数时,它必然会有一个新的值。然而,factor
不是一个正式的参数,那这是什么呢? 再增加一行代码。
var factor = 3
val multiplier = (i:Int) => i * factor
现在factor
参考了函数之外的变量,但是在闭合的范围内。函数引用factor
,每次读取其当前值。 如果函数没有外部引用,那么它本身就会被简单地关闭,不需要外部上下文。
请尝试以下示例程序 -
object Demo {
def main(args: Array[String]) {
println( "multiplier(1) value = " + multiplier(1) )
println( "multiplier(2) value = " + multiplier(2) )
}
var factor = 3
val multiplier = (i:Int) => i * factor
}
将上述程序保存在源代码:Demo.scala中,使用以下命令编译和执行此程序。
D:\>scalac Demo.scala
D:\>scala Demo
multiplier(1) value = 3
multiplier(2) value = 6
Spark记录-Scala函数与闭包的更多相关文章
- Spark记录-Scala函数
Scala函数 Scala有函数和方法. Scala方法是一个具有名称和签名的类的一部分. Scala中的函数是一个可以分配给变量的完整对象. 函数定义可以出现在源文件中的任何位置. 不带参数的函数 ...
- Scala:函数和闭包
http://blog.csdn.net/pipisorry/article/details/52902271 Scala函数 Scala 有函数和方法,二者在语义上的区别很小.Scala 方法是类的 ...
- Spark记录-Scala模式匹配
Scala模式匹配 模式匹配是Scala函数值和闭包后第二大应用功能.Scala为模式匹配提供了极大的支持,处理消息. 模式匹配包括一系列备选项,每个替代项以关键字大小写为单位.每个替代方案包括一个模 ...
- Spark记录-Scala程序例子(函数/List/match/option/泛型/隐式转换)
object func { def main(args:Array[String]):Unit={ //函数赋值给变量时, 必须在函数后面加上空格和下划线. def sayHello(name: St ...
- Spark记录-scala快速入门
1.hello world程序 object HelloWorld { def main(args: Array[String]) { println("Hello,World!" ...
- Spark记录-Scala集合
Scala列表 Scala列表与数组非常相似,列表的所有元素都具有相同的类型,但有两个重要的区别. 首先,列表是不可变的,列表的元素不能通过赋值来更改. 其次,列表表示一个链表,而数组是平的. 具有类 ...
- Spark记录-Scala基础语法
如果您熟悉Java语言语法和编程,那么学习Scala将会很容易.Scala和Java之间最大的句法差异在于行结束字符的分号(;) 是可选的. 当编写Scala程序时,它可以被定义为通过调用彼此的方法进 ...
- Spark记录-Scala介绍
Scala是可扩展语言的缩写,是一种混合功能编程语言. 它由Martin Odersky创建. Scala顺利整合面向对象和函数式语言的功能. Scala被编译后在Java虚拟机上运行. 许多现有公司 ...
- Spark记录-Scala shell命令
1.scala shell命令 scala> :help All commands can be abbreviated, e.g., :he instead of :help. :edit & ...
随机推荐
- mongodb分片集群
第一章 1.mongodb 分片集群解释和目的 一组Mongodb复制集,就是一组mongod进程,这些进程维护同一个数据集合.复制集提供了数据冗余和高等级的可靠性,这是生产部署的基础. 第二章 1. ...
- Python_xlutils.copy
import xlrd import xlwt from xlutils.copy import copy # 读取工作簿 objWB = xlrd.open_workbook(r'C:\Users\ ...
- 按键精灵对APP自动化测试(上)
简单介绍下应用背景:测试安卓app时发现重复点击某一按钮的时候会出现报错,开发修复后提交测试.如果采用手动点击按钮,效率不高,在领导提示下使用按键精灵实现自动操作. 一. 安卓手机按键精灵 ...
- 论文阅读 | Clustrophile 2: Guided Visual Clustering Analysis
论文地址 论文视频 左侧边栏可以导入数据,或者打开以及前保存的结果.右侧显示了所有的日志,可以轻松回到之前的状态,视图的主区域上半部分是数据,下半部分是聚类视图. INTRODUCTION 数据聚类对 ...
- 搭建个人博客 github+hexo
其实相关的教程网上有很多很多,不过就是很多很多,而且技术大神们每个人都写得不一样啊喂,为什么我明明就是一步一步按照教程来的还是有那么多乱七八糟的错?...所以我决定写此篇记录一下我搭建博客的过程以及我 ...
- eclipse实现热部署和热启动
不用每次修改一个class文件就要重启tomcat这么麻烦: http://blog.csdn.net/fuzhongyu2/article/details/52073050
- 《Linux内核设计与实现》Chapter 2 读书笔记
<Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel ...
- C#程序解读
阅读下面程序,请回答如下问题: 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间 ...
- Mysql设置允许外网访问(图文)
1.打开mysql.exe(MySQL Command Line Client),输入密码 2.输入:use mysql; 3.查询host输入: select user,host from user ...
- button 和 submit 的区别
表单提交中button和submit的区别submit是button的一个特例,也是button的一种,它把提交这个动作自动集成了,submit和button,二者都以按钮的形式展现,看起来都是按钮, ...