1.static
scala物static关键字,由object实现类似静态方法的功能--> 类名.方法名
object关键字和class关键字定义的方式相同,但作用不同:
class关键字定义一个类,object声明一个单例对象;
object生成:当前类,当前类$
$这个是“伴生对象”;实现静态方法;可以直接调用;类似static。
2.Scala无void
而是Unit类;
Unit类型、Null类型和Nothing类型
基本说明
数据类型 | 描述 |
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null , Null 类型只有一个实例值null |
Nothing | Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
3.变量
var | val 变量明发 [:变量类型] = 变量值
1.变量类型可省略,会自动推导;
2.类型确定后,不能修改;
3.变量声明时,需初始值;
var是可变的,val是不可变的
4.字符串输出
1.通过+号连接;
2.printf:通过%传值
3.通过$引用 : s"name=$name"
5.数值类型间转换
自动转换:精度小的类型自动转换为精度大的数值类型
基本说明
(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
(2)当我们把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
(3)(byte,short)和char之间不会相互自动转换。
(4)byte,short,char他们三者可以计算,在计算时首先转换为int类型。
强制转换:精度大的数值类型转换为精度小的数值类型。格式y.toXXX
强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
var r2: Int = (10 * 3.5 + 6 * 1.5).toInt
数值类型和String类型间转换
(1)基本类型转String类型(语法:将基本类型的值+"" 即可)
(2)String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)
在Scala中没有Switch,而是使用模式匹配来处理。
函数编程
函数基本语法
Scala函数可以才任何地方定义,函数中也可以定义函数;
Java只能在类中定义方法;
函数和方法的区别
1)核心概念
(1)为完成某一功能的程序指令(语句)的集合,称为函数。
(2)类中的函数称之方法。
(3)方法可以通过 _ 转换为函数
foo _
函数没有重载和重写的概念;方法可以进行重载和重写
val f : Int =>Unit = foo _ //这里就是函数,把方法转换成函数
def foo(a:Int) : Unit = println(a) //方法
//() => { } /直接定义函数
直接函数不能声明返回类型,
val f: Int => Int = (a:Int) = > a * a //定义函数 (a:Int) = > a * a若想有返回值
参数 => 返回值
val f: Int => Int = //变量用来接收函数
带名参数
def test4( sex : String = "男", name : String ): Unit = {
println(s"$name, $sex")
}
// scala函数中参数传递是,从左到右
test4(name="ximenqing") // 带名参数
函数至简原则:能省则省
1)至简原则细节
(1)return可以省略,Scala会使用函数体的最后一行代码作为返回值
(2)返回值类型如果能够推断出来,那么可以省略
(3)如果函数体只有一行代码,可以省略花括号
(4)如果函数无参,则可以省略小括号。若定义函数时省略小括号,则调用该函数时,也需省略小括号;若定时函数时未省略,则调用时,可省可不省。
(5)如果函数明确声明Unit,那么即使函数体中使用return关键字也不起作用
(6)Scala如果想要自动推断无返回值,可以省略等号
(7)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
(8)如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,需要声明返回值类型
高级特性:
1.函数可以定义在任何位置,可以在函数内定义函数;
2.可以把函数当成一个值返回给函数的调用者,函数的调用者就可以在函数的外面去调用这个返回的函数
在其他函数就可以调用了;
val f1:() => Unit = foo()
f1() //调用foo中f()函数
def foo() : () => Unit = {
def f() : Unit = {
println("aaa")
}
f _
}
3.可以把函数当做一个值,传递给另外一个函数;
foo(f _)
def f():Unit ={
println("a")
}
def foo ( x : ()=> Unit) : Unit = {
println(x)
x()
}
4.若一个函数f可以返回一个函数作为返回值,或者可以接受一个(多个)函数作为参数,那么这个函数f就称为高阶函数。
高阶函数
高阶函数(Higher-Order Function)就是操作其他函数的函数。
高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。
Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。
以下实例中,apply() 函数使用了另外一个函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v:
1.作为值的函数
可以像任何其他数据类型一样被传递和操作的函数,每当你想要给算法传入具体动作时这个特性就会变得非常有用。
定义函数时格式:val 变量名 = (输入参数类型和个数) => 函数实现和返回值类型
“=”表示将函数赋给一个变量
“=>”左面表示输入参数名称、类型和个数,右边表示函数的实现和返回值类型
函数可以作为一个参数传入到一个方法当中去
def main(args: Array[String]): Unit = { val myFunc1 = (x:Int) =>{ x * x } val myArray = Array(1,3,5,7,9).map(myFunc1) println(myArray.mkString(",")) } |
//高阶函数————函数作为参数
def calculator(a: Int, b: Int, operator: (Int, Int) => Int): Int = {
operator(a, b)
}
operator: (Int, Int) => Int // 函数,参数(Int, Int) ,返回值Int
2、匿名函数
1)说明
没有名字的函数就是匿名函数,可以直接通过函数字面量(λ 表达式)来设置匿名函数,函数字面量定义格式如下。
作用:
1.作为实参,直接传递给高阶函数
2.直接作为高阶函数的返回值
在 Scala 中,你不需要给每一个函数命名,没有将函数赋给变量的函数叫做匿名函数。
由于 Scala 可以自动推断出参数的类型,所有可以写的跟精简一些
还记得神奇的下划线吗?这才是终极方式
高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在Scala中函数是“一等公民”,所以允许定义高阶函数。这里的术语可能有点让人困惑,我们约定,使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。
最常见的一个例子是Scala集合类(collections)的高阶函数map
val salaries = Seq(20000, 70000, 40000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)
函数doubleSalary
有一个整型参数x
,返回x * 2
。
一般来说,在=>
左边的元组是函数的参数列表,而右边表达式的值则为函数的返回值。在第3行,函数doubleSalary
被应用在列表salaries
中的每一个元素。
为了简化压缩代码,我们可以使用匿名函数,直接作为参数传递给map
:
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)
注意在上述示例中x
没有被显式声明为Int类型,这是因为编译器能够根据map函数期望的类型推断出x
的类型。对于上述代码,一种更惯用的写法为:
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(_ * 2)
既然Scala编译器已经知道了参数的类型(一个单独的Int),你可以只给出函数的右半部分,不过需要使用_
代替参数名(在上一个例子中是x
)
foo(_ + _)
要求:1.匿名只能有两个参数;
2.每个参数只使用了一次;
3.每一个_表示第一个参数,第二个下划线表示第二个参数
只使用一次可以简化:_
x*x*x //这是不能简化的_*_*_,错误的
函数柯里化&闭包
1)说明
函数柯里化Currying:将一个接收多个参数的函数转化成一个接受一个参数的函数过程,可以简单的理解为一种特殊的参数列表声明方式;并且返回接受余下的参数且返回结果为一个新函数的技术。
- 一个普通的非柯里化的函数定义,实现一个加法函数:
scala> def plainOldSum(x:Int,y:Int)=x+y
plainOldSum: (x: Int, y: Int)Int
scala> plainOldSum(1,2)
res0: Int = 3
- 使用“柯里化”技术来定义这个加法函数,原来函数使用一个参数列表,“柯里化”,把函数定义为多个参数列表:
scala> def curriedSum(x:Int)(y:Int)=x+y
curriedSum: (x: Int)(y: Int)Int
scala> curriedSum(1)(2)
res1: Int = 3
当你调用 curriedSum (1)(2)时,实际上是依次调用两个普通函数(非柯里化函数),
第一次调用使用一个参数 x,返回一个函数类型的值,
第二次使用参数 y 调用这个函数类型的值。
- 使用下面两个分开的定义在模拟 curriedSum 柯里化函数:
首先定义第一个函数:
scala> def first(x:Int)=(y:Int)=>x+y
first: (x: Int)Int => Int
然后我们使用参数 1 调用这个函数来生成第二个函数:
scala> val second =first(1)
second: Int => Int = <function1>
scala> second(2)
res2: Int = 3
- 使用 curriedSum 来定义 second
scala> val onePlus=curriedSum(1)_
onePlus: Int => Int = <function1>
下划线“_” 作为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给
调用的参数加一。
scala> onePlus(2)
res3: Int = 3
调用生成的函数,给函数传入参数,即可得到我们想要的结果。
scala 柯里化风格的使用可以简化主函数的复杂度,提高主函数的自闭性,提高功能上的可扩张性、灵活性。可以编写出更加抽象,功能化和高效的函数式代码。
闭包:就是一个函数和与其相关的引用环境(变量)组合的一个整体(实体)
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问不在当前作用域范围内的一个函数。