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函数篇详解的更多相关文章

  1. Scala进阶之路-Scala高级语法之隐式(implicit)详解

    Scala进阶之路-Scala高级语法之隐式(implicit)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们调用别人的框架,发现少了一些方法,需要添加,但是让别人为你一 ...

  2. Scala进阶之路-Scala中的Ordered--Ordering

    Scala进阶之路-Scala中的Ordered--Ordering 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   说道对象的比较,在Java中大家最熟悉不过的就是实现类本身实 ...

  3. Scala进阶之路-Scala中的泛型介绍

    Scala进阶之路-Scala中的泛型介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型.我们不可能一一列举所有的参数类 ...

  4. Scala进阶之路-Scala的基本语法

    Scala进阶之路-Scala的基本语法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.函数式编程初体验Spark-Shell之WordCount var arr=Array( ...

  5. Scala进阶之路-Scala中的枚举用法案例展示

    Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...

  6. Scala进阶之路-Scala中的高级类型

    Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...

  7. Scala进阶之路-Scala特征类与unapply反向抽取

    Scala进阶之路-Scala特征类与unapply反向抽取 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala特征类分析 1>.Unit 答:用于定义返回值类型, ...

  8. PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明

    PHP函数篇详解十进制.二进制.八进制和十六进制转换函数说明 作者: 字体:[增加 减小] 类型:转载   中文字符编码研究系列第一期,PHP函数篇详解十进制.二进制.八进制和十六进制互相转换函数说明 ...

  9. Scala进阶之路-反射(reflect)技术详解

    Scala进阶之路-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的反射技术和Java反射用法类似,我这里就不一一介绍反射是啥了,如果对 ...

随机推荐

  1. 东大OJ-一元三次方程解的个数

    1043: Fixed Point 时间限制: 5 Sec  内存限制: 128 MB 提交: 26  解决: 5 [提交][状态][讨论版] 题目描述 In mathematics, a fixed ...

  2. Map Columns From Different Tables and Create Insert and Update Statements in Oracle Forms

    This is one of my most needed tool to create Insert and Update statements using select or alias from ...

  3. c - 字符串的反转

    1,递归实现 // 递归实现字符串反转(可通过栈的调用来加深理解). char * reverse(char *c) { if(!c) return NULL; int len = strlen(c) ...

  4. C语言对象化编程

    以下为一个引子: C中struct的函数实现,只能用函数指针成员. C结构体内不能有函数的代码,但可以有函数的指针. C/C code Code highlighting produced by Ac ...

  5. About Windows 10 April 2018 Update

    在四月的最后一天,微软终于正式发布了 Windows 10 的又一次重大更新,并命名为 Windows 10 四月更新,轮压哨,我软确实谁也不服:再晚一天,我软改名部门恐怕又要发挥作用了,毕竟我软存在 ...

  6. 91 Testing MySQL学习总结

    91 Testing MySQL学习总结 --------- 在WEB应用方面MySQL是最好的RDBMS(Relational Database Management System什么是数据库?数据 ...

  7. Html5 标签一(文本)

    1.html编辑器:Sublime Text 2.标签(文本) 一 Sublime Text 作用:html编辑器. 下载地址:http://www.sublimetextcn.com/ 二 文本 总 ...

  8. MiUI开发者版刷入xposed框架--简洁方法

    一,首先要确定手机是否解锁 可以去这里查看怎么解锁: http://www.miui.com/unlock/index.html 二,手机系统需要是开发者版,且在安全中心的授权管理打开了ROOT授权 ...

  9. 超文本标记语言HTML

    介绍html文档的基本结构,html常用标签的使用,理解html语言制作网页基本原理. html概述和基本结构 html概述 HTML是 HyperText Mark-up Language 的首字母 ...

  10. 移动App中常见的Web漏洞

    智能手机的存在让网民的生活从PC端开始往移动端转向,现在网民的日常生活需求基本上一部手机就能解决.外卖,办公,社交,银行转账等等都能通过移动端App实现.那么随之也带来了很多信息安全问题,大量的用户信 ...