Scala进阶之路-Scala函数篇详解
Scala进阶之路-Scala函数篇详解
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.传值调用和传名调用
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object CalculateDemo {
- /**
- * 定义传值的方法 :
- * add方法拥有2个Int类型的参数, 返回值为2个Int的和。
- */
- def add(a: Int, b: Int) () = {
- a + b
- }
- /**
- * 定义传参的方法 :
- * add2方法拥有3个参数,第一个参数是一个函数(它拥有2个Int类型的参数,返回值为Int类型的函数), 第二个,第三个为Int类型的参数
- */
- def add2(f:(Int, Int) => Int, a: Int, b: Int) = {
- f(a, b) // f(1, 2) => 1 + 2
- }
- /**
- * 定义传参的方法 :
- * 第一个参数是一个函数(它拥有1个Int类型的参数,返回值为Int类型的函数),第二个为Int类型的参数。
- */
- def add3(a:(Int) => Int, b: Int) = {
- //这里我们将第二个参数作为第一个函数的签名传递进去
- a(b) + b
- }
- /**
- * fxx你们函数是符合add2中的“f:(Int, Int) => Int”这个方法签名的,因此我们可以把它当做第一个参数进行传递
- */
- val f1 = (a: Int, b: Int) => a + b
- /**
- * 定义一个匿名函数,它需要传递一个参数,函数体的返回值是将传入的值乘以10并返回,返回值类型为Int。
- */
- val f2 = (x: Int) => (x * 10):Int
- def main(args: Array[String]): Unit = {
- //传值方式调用
- val res1 = add(100, 10 + 20)
- println(res1)
- //传参方式调用一,我们给匿名函数传参数,最终返回的结果和第二个参数以及第三个参数进行运算
- var res2 = add(f1(10, 20), 30)
- println(res2)
- //传参方式调用二,我们给匿名函数传参数,
- var res3 = add2(f1, 10, 20)
- println(res3)
- //传参方式调用
- val res4 = add3(f2, 8)
- println(res4)
- }
- }
- /*
- 以上代码执行结果如下 :
- 130
- 60
- 30
- 88
- */
二.可变参数
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object VariableParameter {
- /**
- * 定义一个可变参数的方法,参数的类型为任意类型,相当于Java中的Object类,当然你也可以为AnyVal或者AnyRef的子类
- */
- def methodManyParams(args: Any*) = {
- for (item <- args) {
- print(item + "|")
- }
- println()
- }
- /**
- * 可变参数一般放在参数列表的末尾。
- */
- def add(des:String, ints:Int*):Int = {
- var sum = 0
- for (value <- ints){
- sum += value
- }
- print(des)
- sum
- }
- def main(args: Array[String]): Unit = {
- methodManyParams("尹正杰", "大数据", "云计算", "人工智能", "机器学习", "自动化运维",2018)
- var res = add("计算结果 : ", 10, 20, 30, 40)
- println(res)
- }
- }
- /*
- 以上代码执行结果如下 :
- 尹正杰|大数据|云计算|人工智能|机器学习|自动化运维|2018|
- 计算结果 : 100
- */
三.参数的默认值
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object DefaultValuesParameters {
- /**
- * 参数定义时可以指定一个默认值
- * @param path : 指定程序的安装路径
- * @param user : 指定安装的用户
- */
- def installationSoftware(path:String = "D:/yinzhengjie/BigData/Spark",user:String="yinzhengjie") ={
- print(s"安装路径是: $path,当然的安装用户是 : ${user}\n")
- }
- def main(args: Array[String]): Unit = {
- //调用时如果不传递参数,就会使用函数或者方法的默认值
- installationSoftware()
- //调用时,如果传递了参数值,就会使用传递的参数值
- installationSoftware("E:/yinzhengjie/Hadoop/Scala","Administrator")
- //调用时,如果传递了一个参数,那么就会覆盖第一个参数的值
- installationSoftware("/home/yinzhengjie/Spark/Scala")
- //如果想要给指定的参数赋值,可以采用键值对的方式赋值,赋值参数时,参数的名称和方法定义的名称需要保持一致!
- installationSoftware(user = "root")
- //当然赋值的方式可以打乱顺序,但是需要以键值对的方式传递哟!
- installationSoftware(user = "Scala",path = "/home/yinzhengjie/Hadoop/Spark")
- }
- }
- /*
- 以上代码执行结果如下 :
- 安装路径是: D:/yinzhengjie/BigData/Spark,当然的安装用户是 : yinzhengjie
- 安装路径是: E:/yinzhengjie/Hadoop/Scala,当然的安装用户是 : Administrator
- 安装路径是: /home/yinzhengjie/Spark/Scala,当然的安装用户是 : yinzhengjie
- 安装路径是: D:/yinzhengjie/BigData/Spark,当然的安装用户是 : root
- 安装路径是: /home/yinzhengjie/Hadoop/Spark,当然的安装用户是 : Scala
- */
四.高阶函数
高阶函数的定义:将其他函数作为参数或其结果是函数的函数。要注意的是传入的函数必须符合高阶函数参数中定义的函数签名。
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object HigherFunction {
- /**
- * 定义一个高级函数:
- * f: (Int) => String
- * 第一个参数是带一个整型参数返回值为字符串的函数f
- *v: Int
- * 第二个参数是一个整型参数v
- * f(v)
- * 返回值为一个函数“f(v)”。
- */
- def apply(f: (Int) => String, v: Int) = {
- //返回的函数“f(v)”,即将第二个参数作为第一个函数的参数。
- f(v)
- }
- // 定义一个方法, 参数为一个整型参数, 返回值为String
- def layout(args: (Int)):String = {
- "[" + args.toString() + "]"
- }
- def main(args: Array[String]): Unit = {
- //注意,layout传入的参数个数以及返回值类型都必须符合高阶函数apply中定义的第一个参数的函数签名。
- println (apply (layout , 150))
- }
- }
- /*
- 以上代码执行结果如下:
- [150]
- */
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object HigherFunctionDemo {
- def op(f:(Int,Int)=>Int,a:Int,b:Int):Int = {
- f(a , b)
- }
- def add(a:Int,b:Int):Int = {
- a + b
- }
- def sub(a:Int,b:Int):Int = {
- a - b
- }
- def main(args: Array[String]): Unit = {
- val res1 = op(add,10,2)
- val res2 = op(sub,10,2)
- print(s"res1=====> ${res1}\n")
- print(s"res2=====> ${res2}\n")
- }
- }
- /*
- 以上代码执行结果如下 :
- res1=====> 12
- res2=====> 8
- */
HigherFunctionDemo.scala 文件内容(高阶函数案例二,将其他函数作为参数传入)
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object HigherFunctionDemo2 {
- /**
- * 该函数用于计算幂函数
- * powx :
- * 这个是定义高阶函数的名称。
- * n:Int :
- * 这个是高阶函数的参数。
- * (Double)=>Double :
- * 这个是高阶函数返回的匿名函数签名,第一个“(Double)”表示匿名函数的参数,第二个“Double”表示的是返回值类型。
- * (x:Double) =>
- * 从该行往后都是匿名函数的函数体。
- */
- def powx(n:Int): (Double)=>Double = {
- (x:Double) => {
- var sum :Double = 1 //定义Double类型的变量sum
- for(i <- 1 to n) sum *= x //定义运算过程
- sum //返回计算的结果
- }:Double //返回值类型为:Double,我们也可以省略不写哟
- }
- def main(args: Array[String]): Unit = {
- //计算4的二次幂
- val res1 = powx(2)(4)
- println(res1)
- }
- }
- /*
- 以上代码执行结果如下:
- 16.0
- */
HigherFunctionDemo2.scala 文件内容(高阶函数案例二,返回结果是函数的函数)
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.function
- object LinearAlgebra {
- /**
- * 定义线性代数的高阶函数,模拟:y = ax + b
- */
- def line(x1:(Int,Int)=>Int,x2:Int,x3:Int,x4:(Int,Int)=>Int,x5:Int,x6:Int):Int=>Int={
- val a = x1(x2,x3)
- val b = x4(x5,x6)
- def f(args:Int):Int =a * args +b
- //返回函数
- f _
- }
- /**
- * 上面的也可以写成一行,就是返回匿名函数,具体代码如下:
- */
- def line2(x1:(Int,Int)=>Int,x2:Int,x3:Int,x4:(Int,Int)=>Int,x5:Int,x6:Int):Int=>Int={
- //我们也可以返回匿名函数
- (x:Int) =>{
- x1(x2,x3) * x + x4(x5,x6)
- }
- }
- def add(x:Int,y:Int) = x + y
- def sub(x:Int,y:Int) = x - y
- def main(args: Array[String]): Unit = {
- //调用函数
- var res1 = line(add,1,2,sub,3,4)(5)
- var res2 = line2(add,1,2,sub,3,4)(5)
- print(s"res1 =====> ${res1}\n")
- print(s"res2 =====> ${res2}\n")
- }
- }
- /*
- 以上代码执行结果如下:
- res1 =====> 14
- res2 =====> 14
- */
LinearAlgebra.scala 文件内容(使用高阶函数模拟线性代数的实现:"y = ax + b ")
高阶有用的函数用法展示:
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- object HigherFunction {
- def main(args: Array[String]): Unit = {
- var res1 = (1 to 10).map(_ * 0.1)
- print(s"res1 =====> $res1\n")
- println("==========我是分割线=========")
- (1 to 10).map("*" * _).foreach(println)
- println("==========我是分割线=========")
- val arr = Array[Int](1,2,3,4)
- val res2 = arr.reduceLeft(_ - _)
- val res3 = arr.reduceRight(_ - _)
- println("==========我是分割线=========")
- print(s"res2 =====> $res2 \n")
- println("==========我是分割线=========")
- print(s"res3 =====> $res3 \n")
- }
- }
- /*
- 以上代码执行结果如下:
- res1 =====> Vector(0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1.0)
- ==========我是分割线=========
- *
- **
- ***
- ****
- *****
- ******
- *******
- ********
- *********
- **********
- ==========我是分割线=========
- ==========我是分割线=========
- res2 =====> -8
- ==========我是分割线=========
- res3 =====> -2
- */
五.部分参数应用函数
部分参数应用函数定义:如果函数传递所有预期的参数,则表示已完全应用它。如果只传递几个参数并不是全部参数,那么将返回部分应用的函数。这样就可以方便地绑定一些参数,其余的参数可稍后填写补上。
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.basicGrammar
- import java.util.Date
- object PartialParameter {
- /**
- * 定义个输出的方法, 参数为date, message
- */
- def log(date: Date, message: String) = {
- println (s"$date, $message")
- }
- def main(args: Array[String]): Unit = {
- //定义一个日期对象
- val date = new Date()
- /**
- * 调用log 的时候, 传递了一个具体的时间参数, message为待定参数。logBoundDate成了一个新的函数,它需要传递一个String对象。
- *
- */
- val logBoundDate : (String) => Unit = {
- //我们在调用log函数时,值传递了第一个参数,第二个参数我们空出来了,并没有传递,而是指定第二个参数的类型。
- log (date , _: String)
- }
- // 调用logBoundDate 的时候, 只需要传递待传的message 参数即可
- logBoundDate ("I'm Yinzhengjie!")
- //当然你想要传递两个参数,直接调用log函数也是可以的哟!
- log(date,"I'm Yinzhengjie")
- }
- }
- /*
- 以上代码执行结果如下 :
- Mon Jul 23 15:56:44 CST 2018, I'm Yinzhengjie!
- Mon Jul 23 15:56:44 CST 2018, I'm Yinzhengjie
- */
六.柯里化函数(Currying)
柯里化(Currying,以逻辑学家Haskell Brooks Curry的名字命名)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。因此我们可以说柯里化就是高阶函数的一种,而高阶函数不一定就是柯里化函数。
柯里化的好处:有时候,你想要用柯里化来把某个函数参数单拎出来,以提供更多用于类型推断的信息。
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.function
- object MyCurrying {
- /**
- * 常规方法求两个参数和的函数:
- * 我们看下这个方法的定义, 求2个数的和,需要传递两个参数
- */
- def add1(x: Int, y: Int) = x + y
- /**
- * 现在我们把上面的函数变一下形 :
- * 使用柯里化(Currying)两个参数和的函数:
- */
- def add2(x:Int)(y:Int) = x + y
- /**
- * 分析下其演变过程 :
- * (y: Int) => x + y 为一个匿名函数, 也就意味着 add3 方法的返回值为一个匿名函数.
- */
- def add3(x: Int) = (y: Int) => x + y
- def main(args: Array[String]): Unit = {
- var res1 = add1(10,20)
- println(res1)
- /**
- * 这种方式(过程)就叫柯里化。经过柯里化之后,函数的通用性有所降低,但是适用性有所提高。
- */
- var res2 = add2(10)(20)
- println(res2)
- /**
- * 调用方式需要进行两次传值操作,有点类似我们之前说的部分参数应用函数
- */
- val res3 = add3(10)
- print(res3(20))
- }
- }
- /*
- 以上代码输出结果如下:
- 30
- 30
- 30
- */
七.偏函数
被包在花括号内没有 match 的一组 case 语句是一个偏函数,它是 PartialFunction[-A, +B]的一个实例,“-A” 代表参数类型,“+B” 代表返回类型,常用作输入模式匹配。
- /*
- @author :yinzhengjie
- Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
- EMAIL:y1053419035@qq.com
- */
- package cn.org.yinzhengjie.function
- object MyPartialFunction {
- /**
- * 定义一个函数,要求传入的参数是一个String类型,而返回值类型是Int类型
- */
- def func(language:String):Int = {
- if (language.equals("Python")) 100
- else if (language.equals("Golang")) 200
- else if (language.equals("Java")) 300
- else if (language.equals("Shell")) 400
- else if (language.equals("Scala")) 500
- else -1
- }
- /**
- * 上面的函数我们也可以用关键字match+case组合来匹配用户的输入值
- */
- def func2(num: String) : Int = num match {
- //case 可以匹配传进来的参数,即传入的字符串是"Python"就返回100.
- case "Python" => 100
- case "Golang" => 200
- case "Java" => 300
- case "Shell" => 400
- case "Scala" => 500
- //case _ 表示匹配默认情况,即以上条件均不满足时会走下面的这个语句哟
- case _ => -1
- }
- /**
- * 接下来我们用偏函数重写上面的func函数的功能
- * 其中PartialFunction就是偏函数的关键字,里面的第一个参数是调用者输入参数的类型(String),而第二个参数是返回值类型(Int类型)
- */
- def func3:PartialFunction[String,Int] = {
- //case 可以匹配传进来的参数,即传入的字符串是"Python"就返回100.
- case "Python" => 100
- case "Golang" => 200
- case "Java" => 300
- case "Shell" => 400
- case "Scala" => 500
- //case _ 表示匹配默认情况,即以上条件均不满足时会走下面的这个语句哟
- case _ => -1
- }
- def func4:PartialFunction[Any,Int]={
- //case也可以匹配传进来的类型,如果是Int类型就将这个参数乘以2并返回,如果这个参数不是Int类型的话就返回-1
- case i:Int => i * 2
- case _ => -1
- }
- def main(args: Array[String]): Unit = {
- var res1 = func("Python")
- println(res1)
- var res2 = func2("Python")
- println(res2)
- var res3 = func3("Python")
- println(res3)
- var arr = Array[Any](1,"yinzhengjie",3,"尹正杰",5)
- var res4 = arr.collect(func4)
- println(res4.toBuffer.toString())
- }
- }
- /*
- 以上代码输出结果如下 :
- 100
- 100
- 100
- ArrayBuffer(2, -1, 6, -1, 10)
- */
Scala进阶之路-Scala函数篇详解的更多相关文章
- Scala进阶之路-Scala高级语法之隐式(implicit)详解
Scala进阶之路-Scala高级语法之隐式(implicit)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们调用别人的框架,发现少了一些方法,需要添加,但是让别人为你一 ...
- Scala进阶之路-Scala中的Ordered--Ordering
Scala进阶之路-Scala中的Ordered--Ordering 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 说道对象的比较,在Java中大家最熟悉不过的就是实现类本身实 ...
- Scala进阶之路-Scala中的泛型介绍
Scala进阶之路-Scala中的泛型介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型.我们不可能一一列举所有的参数类 ...
- Scala进阶之路-Scala的基本语法
Scala进阶之路-Scala的基本语法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.函数式编程初体验Spark-Shell之WordCount var arr=Array( ...
- Scala进阶之路-Scala中的枚举用法案例展示
Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...
- Scala进阶之路-Scala中的高级类型
Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...
- Scala进阶之路-Scala特征类与unapply反向抽取
Scala进阶之路-Scala特征类与unapply反向抽取 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala特征类分析 1>.Unit 答:用于定义返回值类型, ...
- PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
PHP函数篇详解十进制.二进制.八进制和十六进制转换函数说明 作者: 字体:[增加 减小] 类型:转载 中文字符编码研究系列第一期,PHP函数篇详解十进制.二进制.八进制和十六进制互相转换函数说明 ...
- Scala进阶之路-反射(reflect)技术详解
Scala进阶之路-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的反射技术和Java反射用法类似,我这里就不一一介绍反射是啥了,如果对 ...
随机推荐
- bugkuct部分writeup 持续更新
6307 校赛被打击到自闭,决心好好学习. web部分题目. 1.web2 地址 http://123.206.87.240:8002/web2/ 既然是第一个题我们应该采取查看源码的方式进行,右键之 ...
- PAT甲题题解-1025. PAT Ranking (25)-排序
排序,求整体的排名和局部的排名整体排序,for循环一遍同时存储整体目前的排名和所在局部的排名即可 #include <iostream> #include <cstdio> # ...
- Scrum Meeting NO.5
Scrum Meeting No.5 1.会议内容 暂时料理完了编译,可以写软工了.说多了都是泪T_T 2.任务清单 徐越 序号 近期的任务 进行中 已完成 1 修改url名.参数 √ 2 学习Jso ...
- 第四次Scrum meeting
第四次Scrum meeting 会议内容: 沟通方面:与学霸在线组.学霸手机客户端组进行沟通,了解现阶段各个小组的进度,并针对接口结构方面进行调整 前后端:我们完全可以是不需要界面的,但是为了用户的 ...
- 2-Sixteenth Scrum Meeting-20151216
任务安排 成员 今日完成 明日任务 闫昊 写完学习进度记录的数据库操作 写完学习进度记录的数据库操作 唐彬 编写与服务器交互的代码 编写与服务器交互的代码 史烨轩 获取视频url 余帆 本地 ...
- 【Alpha阶段】M1事后报告
时间:2015-11-13 23:30 地点:七公寓一楼会议室 参与人员:窝窝头全体成员(王若愚因事请假) 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述 ...
- “人向猿进阶”之软件工程第三课----WORDCOUNT.EXE统计程序
---恢复内容开始--- WC项目要求 这个项目要求写一个命令行程序,模仿已有的wc.exe的功能,并加以扩充,给出某程序设计源语言文件的字符数.单词数和行数.给实现一个统计程序,它能正确统计程序文件 ...
- 蜗牛慢慢爬 LeetCode 25. Reverse Nodes in k-Group [Difficulty: Hard]
题目 Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. ...
- 【IneliJ 】使用IneliJ IDEA 2016将Java Web项目导出为War包
本文记录使用IDEA导出war包的过程以及碰到问题的解决办法 虽说现在改用IDEA进行开发了,但还是用eclipse打war包 ….囧 这样下去不是办法... 于是今天就试着使用IDEA进行打包. 项 ...
- 奔小康赚大钱 HDU - 2255(最大权值匹配 KM板题)
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...