Scala方法与函数使用和定义详解
作者:Cry丶 发布时间:2021-10-05 06:34:12
一、方法的定义
1.方法体中最后返回值可以使用return, 如果使用了return, 那么方法体的返回值类型一定要指定
2.如果方法体重没有return, 默认将 方法体中最后一行计算的结果当作返回值返回. 方法体的返回值可以省略, 会自动推断
3.定义方法传入的参数一定要指定类型
4.方法的方法体如果只有一行, 那么方法体的“{…}”可以省略
5.如果定义方法时, 省略了方法名称和方法体之间的"=", 那么无论方法体最后一行计算的结果是什么, 都会被丢弃, 返回Unit
def max(a: Int, b: Int) = {
if (a > b) {
"哈哈"
} else {
b
}
}
// 语法糖: 方法定义
def max0(a: Int, b: Int) = if (a > b) a else b
注:记住def定义的格式,按着格式敲即可,不要纠结
二、递归方法
递归方法必须要显示指定返回体的类型
def fun2(num: Int): Int = {
if (num == 1)
num
else
num * fun2(num - 1)
}
// 语法糖
def fun2(num:Int) : Int = if (num == 1) num else num * fun2(num - 1)
注:编译器无法直接推断出你最终递归的结果类型,所以需要你显示指定
三、参数有默认值的方法
1.默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值
2.如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称
def fun3(a: Int = 10, b: Int) = {
println(a + b)
}
四、可变参数个数的函数
多个参数之间逗号分开
def fun4(elements: Int*) = {
println(elements)
elements.foreach(i => println(i))
// 当匿名函数的元素只用到一次的时候, 可以用_简写
elements.foreach(println(_))
// 当方法入参为单个参数时且正好是匿名函数的元素时, 进一步简写
elements.foreach(println)
var sum = 0;
for (elem <- elements) {
sum += elem
}
sum
}
五、匿名函数
注意函数的写法与方法的写法有些许的不同,出现 => 符号就认为是函数,但实际使用上效果并无不同,仅仅是语法上的细微区别
原生的匿名函数写法(基本不用):(Int, Int) => Int就是他的类型
/**
* 原生的匿名函数写法(基本不用)
* @return
*/
def fun: (Int, Int) => Int = (a: Int, b: Int) => {
a + b
}
常用的匿名函数写法: 可以将匿名函数返回给定义的一个变量, 看到“=>”就是匿名函数, 多用于方法的参数是函数时(函数指针),用匿名函数简写
/**
* 常用的匿名函数写法: 可以将匿名函数返回给定义的一个变量, 看到“=>”就是匿名函数
* 多用于方法的参数是函数时(函数指针),用匿名函数简写
*
* @param args
*/
def main(args: Array[String]): Unit = {
/**
* 有参数匿名函数
*/
val value1: (Int) => Unit = (a: Int) => {
println(a)
}
value1(1)
/**
* 无参数匿名函数
*/
val value2 = () => {
println("我爱学习")
}
value2()
/**
* 有返回值的匿名函数
*/
val value3 = (a: Int, b: Int) => {
a + b
}
println(value3(4, 4))
}
六、嵌套方法
/**
* 嵌套方法
* 例如:嵌套方法求5的阶乘
*/
def fun5(num: Int) = {
def fun6(a: Int, b: Int): Int = {
if (a == 1) {
b
} else {
fun6(a - 1, a * b)
}
}
fun6(num, 1)
}
七、偏应用函数(部分应用函数)
某些情况下, 方法中参数非常多, 调用这个方法非常频繁, 每次调用只有固定的某个参数变化, 其他都不变, 可以定义偏应用来实现
def showLog(date :Date, log :String)= {
println(s"date is $date, log is $log")
}
def main(args: Array[String]): Unit = {
val date = DateUtil.date(new Date())
showLog(date,"当前时间")
// 想要调用log, 以上变化的是第二个参数, 可以用偏应用函数处理
// 把showLog()方法定义为偏应用函数
val logWithDate = showLog(date,_:String)
// 第二种函数写法
def logWithDate2 = showLog(date,_:String)
logWithDate("偏应用函数-log11")
logWithDate("偏应用函数-log22")
logWithDate("偏应用函数-log33")
}
八、高阶函数
函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数.
/**
* 普通的方法
*
* @param a
* @param b
* @return
*/
def fun(a: Int, b: Int): Int = {
a + b
}
/**
* 使用 _把方法强转为一个函数
*/
private val function: (Int, Int) => Int = fun _
/**
* 函数的参数是函数: 函数的类型 (Int, Int) => Int, 记住: 方法的引用仅为方法本身,需要重新赋实参
*
* @param f 函数作为参数
* @param a
* @return
*/
def fun1(f: (Int, Int) => Int, a: Int): Int = {
f(a, 100)
}
/**
* 函数的返回是函数: 必须要显示地写出返回值类型, 或者使用 f2 _
*
* @param a
* @param b
* @return
*/
def fun2(a: Int, b: Int): (Int, Int) => Int = {
// 在内部定义了一个方法
def f2(v1: Int, v2: Int): Int = {
v1 + v2 + a + b
}
f2
}
/**
* 函数的参数是函数,函数的返回是函数
*
* @param f
* @return
*/
def fum3(f: (Int, Int) => Int): (String, String) => String = {
val i = f(1, 2)
def fun1(s1: String, s2: String): String = {
s1 + "@" + s2 + "$" + i
}
fun1
}
/**
* 函数入口
*
* @param args
*/
def main(args: Array[String]): Unit = {
// 显示声明过的函数作为参数
println("显示声明过的函数作为参数: " + fun1(fun, 100))
// 匿名函数作为参数: 匿名函数入参的类型可以省略不写
println("匿名函数作为参数: " + fun1((a: Int, b: Int) => {
a * b
}, 100))
// 返回值是一个函数
println("返回值是一个函数: " + fun2(1, 2)(3, 4))
// 入参和出参都是函数
println("入参和出参都是函数: " + fum3(fun)("hello", "scala!"))
println("入参和出参都是函数: " + fum3((a, b) => a * b)("hello", "scala!"))
}
笔者注:高阶函数这块内容会相对较为难以理解,可以先记住这种结构
九、柯里化函数
柯里化函数: 本质上就是对返回值是函数的方法的一种简化写法
def fun7(a: Int, b: Int)(c: Int, d: Int) = {
a + b + c + d
}
/**
* 函数入口
*
* @param args
*/
def main(args: Array[String]): Unit = {
println(fun7(1, 2)(3, 4))
}
注:fun7(1, 2)(3, 4)可以理解成先运算fun7(1,2)返回了一个fun7函数对象,再对他进行参数(3,4)的赋值
来源:https://crycrycry.blog.csdn.net/article/details/128131070


猜你喜欢
- 将Fragment与Layout结合使用,一般都是主Activity以frame填充Activity的方式交互管理Fragment :1.由
- 使用的是iTextSharp添加PDF水印,由于是接口动态生成PDF,所以采用的是全部是内存流的形式,而且水印是平铺是。iTextSharp
- Java 读取外部资源的方法详解在Java代码中经常有读取外部资源的要求:如配置文件等等,通常会把配置文件放在classpath下或者在we
- 1、Android屏幕常亮/点亮 //保持屏幕常亮 PowerManager pm = (PowerManager) getSystemSe
- c#数据绑定之将datatabel的data添加listView中,简要的通过代码应用了DataTable,DataTableColumns
- android中提供了4中动画: AlphaAnimation 透明度动画效果 ScaleAnimation 缩放动画效果 Translat
- 目录前言connectTimeout:callTimeout:pingIntervalwriteTimeoutreadTimeout总结前言
- 稳定度(稳定性)一个排序算法是稳定的,就是当有两个相等记录的关键字R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前
- 可能经常看面经的同学都知道,面试所遇到的排序算法,快速排序占主要位置,热度只增不减啊,其次就是归并和堆排序。其实以前写过一篇排序的文章,写的
- 本文实例讲述了Android图片处理的方法。分享给大家供大家参考,具体如下:package cn.szbw.util;import Andr
- 场景发布微服务的操作一般都是打完新代码的包,kill掉在跑的应用,替换新的包,启动。spring cloud 中使用eureka为注册中心,
- 本文实例讲述了C#实现将窗体固定在显示器的左上角且不能移动的方法。分享给大家供大家参考。具体实现方法如下:using System;usin
- 一、题目给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑
- 我们很多时候会碰到这样的问题,使用多线程刷一个表的数据时需要多个线程不能重复提取数据,那么这个时候就需要使用到线程的排他锁了。在c#里面其实
- 线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核
- 需求分析文档可以和项目一起进行版本管理文档可以在线访问文档可以与springboot项目集成,不需要分开部署MarkDown支持文档跟随,打
- 一般我们在controller层调用service时,只需要使用@Autowired注解即可,例如如下代码我们经常看到:@RestContr
- 一、先来看看效果演示二、实现原理:这个其实不难实现,通过一个定时器不断调用TextView的setText就行了,在setText的时候播放
- 本文实例讲述了Java ThreadLocal类应用。分享给大家供大家参考,具体如下:一 点睛ThreadLocal,是Thread Loc
- tomcat中文乱码问题这几天测试的兄弟发现了项目中存在乱码问题 经过排查发现是tomcat中的问题 于是在server.xml中添加了如下