Scala学习笔记(2)
来源:互联网 发布:支付宝与淘宝解绑不了 编辑:程序博客网 时间:2024/05/21 12:46
Scala基本语言特性
相比Java
、C++
等语言,Scala
融合了OOP
、FP
等编程范式,同时语法上更灵活。
语法基础(概览)
- Scala语言中不强制要求分号,可以依行断句,只有一行带有多个语句时才要求分号隔开。
- 使用
var
、val
定义变量
、常量
,类型可以由编译器推导,也可以显式指定。定义变量时甚至可以省略var
、val
关键字,无关键字时定义的变量默认即为val
,在定义变量的同时就需要初始化变量,否则报错(抽象类中除外)。 - 使用
def
关键字定义方法,var
、val
定义函数,需要注意的是使用var
定义的函数是可以更改实现的,但def
定义的方法一经定义实现就不可改变。 - 没有自增/自减操作符。
- 所有类型皆为对象,基础类型如
Int
、Double
等都是类,函数/方法返回值的空类型为Unit
,相当于Java/C++中的void
。 - 没有原生enum类型,应继承枚举助手类
Enumeration
。 - 不提供类似Java/C++中的三目运算符,但
if
语句表达式带有返回值,可以实现类似效果。 - 访问类成员权限默认为
public
,因而没有public
关键字,但有private
和protected
关键字,作用与Java大致相同,但支持更细粒度的权限控制。 - 可以使用操作符作为函数名,达到类似C++/C#中操作符重载的效果。
- 类的成员变量可以与方法名称相同。
Hello World
创建文件Test.scala
,输入以下代码:
object Test { def main(args: Array[String]): Unit //带有等号的方法可以省略返回值类型由编译器进行推导 = println("Hello World!")}
与Java类似,Scala也是从主方法main
中开始执行整个程序,不过main方法并不定义在类中,而是定义在单例对象中(使用object关键字创建单例对象)。
将主方法写在class中能够通过编译,但生成的字节码文件在执行时会出错。
也可以不手动定义main方法而去让伴生对象继承App
特质,即可直接执行代码语句,例如:
object Test extends App { println("Hello World!")}
单例对象的名称可以与源码文件的文件名不同。
方法(Method)
与Java不同,Scala中同时支持函数
与方法
(Java只有方法而没有真正意义上的”函数”,只有与”函数”类似的”静态方法”)。
方法由def
关键字定义,可以被def方法、val函数重写。一个典型的方法格式如下:
def methodName(args: Type):Type = { /* function_body */}
Scala中方法体不需要显式使用return
关键字来给出方法返回值,编译器会将函数体的最后一句代码推导出类型做为整个函数的返回值。
对于有返回值的方法,必须要在方法定义中加入等号,否则编译器不会推导返回值。
即使方法的返回值为Unit
,只要显式指定了返回值类型,则必须在方法体中加入等号。
方法和函数的形参不需要也不能使用val
、var
关键字声明,只需写明类型即可。
在Scala中,方法允许省略参数,空的参数表可以直接省略,如:
def getNum: Int = 100def getNum(): Int = 100 //以上两个定义作用相同,但只能存在一个
无参方法与空参方法只能存在一个,但二者在使用方式上略有不同,无参方法在调用时只能直接使用方法名,在方法名后加上括号调用就会出错;但空参方法既可以使用带有括号的方法调用方式,也可以省略括号,例如:
scala> def getNum: Int = 100 //定义了方法 getNum: IntgetNum: Intscala> getNum //正确,返回 100res0: Int = 100scala> getNum() //错误,提示 error: Int does not take parameters<console>:12: error: Int does not take parameters getNum() ^scala> def getNum(): Int = 200 //定义了方法 getNum(): IntgetNum: ()Intscala> getNum //正确,返回 200res1: Int = 200scala> getNum() //正确,返回 200res2: Int = 200
同时,无参方法不能与已有字段名称相同(编译报错),而空参方法允许带有同名的字段。
需要注意的是,在Scala中,赋值表达式的值为Unit
,而不是类似Java/C++中的以被赋值的变量类型为表达式的值。例如:
scala> var _num = 0_num: Int = 0scala> def testNum(num: Int): Int = _num = num //由编译器推断出的返回值类型为Unit<console>:12: error: type mismatch;found : Unitrequired: Int def testNum(num: Int): Int = _num = num ^
参数默认值
在Scala中,方法中参数允许带有默认值:
scala> var num = 100num: Int = 100scala> def setNum(p: Int = 0) { num = p } //方法的参数不能由默认值进行类型推导,即使给参数写明了默认值,也依然需要显式指明类型setNum: (p: Int)Unitscala> setNum() //对于有参数的方法,即使参数带有默认值使得参数表可以为空但在调用时依然不能省略括号,否则报错scala> println(num)0 //输出0
如果一个方法中包含多个同类型并带有默认值的参数,调用时默认匹配第一个参数:
scala> def func(num1: Int = 100, num2: Int = 200) = println(s"$num1 $num2")func: (num1: Int, num2: Int)Unitscala> func(300)300 200
具名参数
在Scala中,调用方法时可以在参数表中写明参数的名称,该特性被称为”具名参数”。
对于方法中包含多个同类型并带有默认值参数的情况下,使用该特性可以显式指定要传入的是哪一个参数:
scala> func(num2 = 300)100 300
与C++不同,Scala中,方法参数的默认值不需要连续,参数的默认值可以交错出现,甚至是颠倒参数顺序:
scala> def func(int: Int, str: String = "String", char: Char, double: Double = 123.0) = println(s"$int $str $char $double")func: (int: Int, str: String, char: Char, double: Double)Unitscala> func(100, 'c')<console>:12: error: not enough arguments for method func: (int: Int, str: String, char: Char, double: Double)Unit.Unspecified value parameter char. func(100, 'c') ^scala> func(int = 100, char = 'c') //对于默认参数不连续的方法,需要使用"具名参数"100 String c 123.0
默认参数与方法重载
在Scala中,若一个带有默认的参数的方法省略默认参数时签名与一个已经存在的方法相同,编译器并不会报错(C++编译器则会报错),而是在调用方法时优先使用无默认值的版本(处理逻辑类似于C#):
object Main extends App { def func() = println("No Args") def func(num: Int = 100) = println(num) func()}
输出结果:
No Args
函数(Function)
在Scala中函数使用var``val
关键字定义,即函数是一个存储了函数对象的字段。
一个典型的函数定义如下:
var functionName: FuncType = 符合签名的方法/函数/Lambda
Scala中的函数类型为Function
,根据参数数目的不同,Scala中提供了Function0[+R]
(无参数)到Function22[-T1, ..., -T22, +R]
共23种函数类型,即Scala中的函数,最多可以拥有22个参数。
与方法不同,函数不能够带有默认值。
需要注意的是,函数不允许省略参数,因为函数名做为表达式时的语义为函数名所代表的函数内容而非函数调用。空参函数的括号不可省略,直接使用函数名并不代表调用空参函数,比如:
scala> var show100: () => Int = () => 100show100: () => Int = <function0>scala> show100 //直接使用函数名得到的是函数对象而非调用函数res0: () => Int = <function0>scala> show100()res1: Int = 100
在Scala中,可以直接使用Lambda创建匿名函数后立即使用:
scala> ((str: String) => println(str))("Hello World!")Hello World!
与C++中的Lambda用法类似:
#include <iostream>using namespace std;int main(void){ [](const string& str) { cout << str << endl; } ("Hello World!"); return 0;}
然而在C#中,Lambda需要创建对象或显式指明类型才能使用,同样的语句需要写成:
using System;class Test{ static void Main(string[] args) => new Action<string>(str => Console.WriteLine(str))("Hello World!"); //或者写成 ((Action<string>)(str => Console.WriteLine(str)))("Hello World!");}
函数组合
在Scala中,函数允许进行组合。
函数组合有两种方式,a compose b
实际调用次序为a(b())
,a andThen b
实际调用次序为b(a())
。
需要注意的是,方法不能直接进行组合,需要将其转化为函数(方法名之后加_
符号)。
object Main extends App { def add(num: Int) = num + 100 def double(num: Int) = num * 2 //只有函数能进行组合,方法需要加"_"符号转化成函数 var compose = add _ compose double var andThen = add _ andThen double println(compose(100) == add(double(100))) println(andThen(100) == double(add(100)))}
输出结果:
true
true
传名参数(By-name Parameter)
当一个方法接收的参数为空时,该参数即为传名参数(By-name Parameter),如下所示:
def func(arg: => T) ...
可以使用传名参数可以接收任意数量的代码,如下所示:
object Main extends App { def show(args: => Unit) = args //单行语句可直接作为参数 show(println("123")) //多行语句可放在大括号中 show { println("456") println("789") }}
运行结果:
123
456
789
函数作为参数
Scala为函数式编程语言,在Scala中函数对象可以直接作为参数传递。
当函数作为参数存在时,传名参数与普通的空参函数参数定义不能同时存在,如下定义只能存在一个:
def func(arg: () => T) = argdef func(arg: => T) = argvar func: (() => T) => T = (arg: () => T) => arg
在接收参数时,空参函数参数只能接收同样空参的函数,即() =>
不能被省略,而传名参数则无此限制。
类型系统
在Scala中,所有的类型皆为对象,所有类型都从根类Any
继承,Any
有AnyVal
和AnyRef
两个子类。
在Scala中,基础类型如Int
、Float
、Double
、Unit
等全部从AnyVal
类中派生,因而可以直接在泛型中直接使用这些类作为类型参数。
同时,Scala中提供了隐式转换(ImplicitConversion)
来保证Int``Float``Double
等类型之间可以自动进行转换。
基础类型与字符串(String)等类型之间的转换也由类提供的成员函数进行,如将数值与字符串相互转换可以使用如下代码:
var str = 100.toStringvar num = str.toInt
在Scala中,所有的基础类型之外的引用类型派生自类AnyRef
。
底类型(Bottom)
与Java不同,Scala中存在底类型(bottom)。底类型包括Nothing
和Null
。
Nothing
是所有类型Any
的子类型,定义为final trait Nothing extends Any
。Nothing
特质没有实例。Null
是所有引用类型AnyRef
的子类型,定义为final trait Null extends AnyRef
。Null
特质拥有唯一实例null
(类似于Java中null
的作用)。
可空类型
在Scala中,使用Option[T]
表示可空类型,Option[T]
包含两个子类,Some[T]
和None
,分别代表值存在/值不存在。
对Option[T]
类型使用getOrElse()
方法来获取存在的值或是当值不存在时使用指定的值,如下所示:
scala> var str1: Option[String] = "test"<console>:10: error: type mismatch; //赋值失败,Option[T]只能接收Option及其子类found : String("test")required: Option[String] var str1: Option[String] = "test" ^scala> var str1: Option[String] = Option("test")str1: Option[String] = Some(test)scala> var str2: Option[String] = Nonestr2: Option[String] = Nonescala> println(str1 getOrElse "Get Value Failed!")testscala> println(str2 getOrElse "Get Value Failed!")Get Value Failed! //输出getOrElse()方法中设定的值
可空类型也可以用于模式匹配中,如下代码所示:
var str = 100.toStringvar num = str.toInt
在Scala中,所有的基础类型之外的引用类型派生自类AnyRef
。
底类型(Bottom)
与Java不同,Scala中存在底类型(bottom)。底类型包括Nothing
和Null
。
Nothing
是所有类型Any
的子类型,定义为final trait Nothing extends Any
。Nothing
特质没有实例。Null
是所有引用类型AnyRef
的子类型,定义为final trait Null extends AnyRef
。Null
特质拥有唯一实例null
(类似于Java中null
的作用)。
可空类型
在Scala中,使用Option[T]
表示可空类型,Option[T]
包含两个子类,Some[T]
和None
,分别代表值存在/值不存在。
对Option[T]
类型使用getOrElse()
方法来获取存在的值或是当值不存在时使用指定的值,如下所示:
scala> var str1: Option[String] = "test"<console>:10: error: type mismatch; //赋值失败,Option[T]只能接收Option及其子类found : String("test")required: Option[String] var str1: Option[String] = "test" ^scala> var str1: Option[String] = Option("test")str1: Option[String] = Some(test)scala> var str2: Option[String] = Nonestr2: Option[String] = Nonescala> println(str1 getOrElse "Get Value Failed!")testscala> println(str2 getOrElse "Get Value Failed!")Get Value Failed! //输出getOrElse()方法中设定的值
可空类型也可以用于模式匹配中,如下代码所示:
object TestOption extends App { var s = List(Some(123), None) for (num <- s) num match { case Some(x) => println(x) case None => println("No Value") }}
运行结果:
123
No Value
- Scala学习笔记2
- Scala学习笔记(2)
- Scala学习笔记(2)
- Scala学习笔记2--类
- Scala学习笔记(2)
- scala学习笔记(2)
- scala学习笔记2 数组
- Scala学习笔记2 (Lang上篇)
- Scala学习笔记2 (Lang下篇)
- Scala学习笔记2 (Lang上篇)
- Scala学习笔记2 (Lang下篇)
- Scala学习笔记2 (Lang上篇) (zhuan)
- Scala 学习笔记(2)-Hello Word!
- Scala学习笔记2 (Lang下篇)
- Scala学习笔记2 (Lang上篇)
- Scala学习笔记-2 开始编码
- Scala学习笔记1
- scala语言学习笔记
- android Activity的启动模式 作用简析+demo详解
- Scala学习笔记(1)
- adb和samba和struts2的关联
- R语言入门班
- 在MacOS下Python安装lxml报错找不到头文件 xmlversion.h 的解法方法
- Scala学习笔记(2)
- OpenCV人脸识别facerec源码分析2——LBPH概述
- 项目常用Javascript分享,包含常用验证和Cookie操作
- Intellij IDEA快捷键
- PaaS优点与限制(3)
- Spring MVC,拦截器实现session控制
- dijkstra算法的应用(poj2387)+堆优化【还没学C艹很尴尬,不理解的先不写了,未完,待续...】
- hdu 1257 最少拦截系统 贪心
- 单链表倒置