函数
函数声明
def 函数名(参数:参数类型...)[:返回值类型]{
//方法实现
}
标准函数
def sum(x:Int,y:Int):Int={
return x+y
}
等价于
def sum(x:Int,y:Int)={
x+y
}
scala可以自动推断返回值类型,如果省略返回值类型,return也必须省略。
可变长参数
def sum(values:Int*)={
var res=0
for(i <- values){
res+=i
}
res
}
等价于
def sum(values:Int*)={
values.sum
}
可变长参数和java类似,必须放在参数声明的最后一个,可以将其作为一个数组理解。
命名参数
def sayHello(msg:String,name:String){
print(s"$msg~$name")
}
在给参数赋值时可以自己指定参数名来选择要赋值的对象
sayHello("hello","张三")
sayHello(name="张三",msg="hello")
参数默认值
def sayHello(msg:String="你好",name:String="张三"){
print(s"$msg~$name")
}
在声明函数时可以给定参数默认值,在使用时可以将默认值覆盖
sayHello()
sayHello("吃了吗","李四")
内嵌函数
def fac(x:Int):Int={
def mul(i:Int):Int={
if(i>1){
i*mul(i-1)
}else{
1
}
}
mul(x)
}
柯里化(掌握)
柯里化是把接收多个参数的函数变成接收一个单一参数的函数,并且返回接收余下的参数的函数作为结果。
def sum(x:Int,y:Int)={
x+y
}
转化为柯里化写法
def sum(x:Int)(y:Int)={
x+y
}
sum(1)(2)
var s=sum(1)(_) ---返回一个函数作为结果
var s=sum _
var s1=s(1)
var s2=s1(2)
print(s2) ---结果为3
匿名函数|方法(重点)
没有方法名,只有参数类型和返回值类型的函数,通常使用匿名函数的形式声明一个函数式变量。
scala> var s=(x:Int,y:Int)=>{x+y}
s: (Int, Int) => Int = <function2>
scala> s(1,2)
res0: Int = 3
def 关键字可以定义⼀个函数式变量。也可以声明⼀个标准⽅法。
def sum(x:Int,y:Int):Int = {
return x+y
}
def sum=(x:Int,y:Int)=>x+y
var sum=(x:Int,y:Int)=>x+y
var sum:(Int,Int)=> Int = (x,y)=> x+y
var sum = ((x,y)=> x+y):(Int,Int)=> Int
通过上述变换可以推导出 函数可以转换为变量,因此可以使⽤var或者val修饰函数式变量,⼜因为
函数式变量是函数,所以可以使⽤def修饰。
def method(op:(Int,Int)=>Int)(x:Int,y:Int)={
op(x,y)
}
val result01 = method((x,y)=>x+y)(1,2)
val result02 = method((x,y)=>x*y)(1,2)
println(result01)
println(result02)
def method(x:Int,y:Int,f:(Int,Int)=>Int):Int={
f(x,y)
}
var f=(x:Int,y:Int)=>{x+y}
method(1,2,f)
结果为 3
类
由于Scala没有静态方法和静态类,通过object去定义静态方法或者静态对象。
单例类
单例类使用object修饰,所有声明在object中的方法都是静态方法,类似于java中声明工具类的引用。
object HelloUtil {
def main(args: Array[String]): Unit = {
sayHello("aaa")
}
def sayHello(name:String):Unit={
println("hello~ "+name)
}
}
单例类中所有方法都是静态的,可以直接使用类名.调用 (HelloUtil.sayHello(“张三”))
单例类对象在创建时不能new,直接赋值即可。 var s=HelloUtil (一般直接调用方法,不创建对象)
类
class User01(){ ---默认构造器,不写默认创建无参构造器(看成无参构造)
var id:Int = _
var name:String = _
var age:Int = _
def this(id:Int,name:String,age:Int){ ---扩展构造器
this()
this.id=id
this.name=name
this.age=age
}
}
var s = new User01()
var s1 = new User01
var s2 = new User01(1,"aaa",18)
print(s"${s2.id} \t ${s2.name} \t ${s2.age}")
必须要求在构造⽅法的第⼀⾏显式调⽤this(),其中 _ 表示参数赋值为默认值
类上声明(默认构造器)
⼀旦类上声明了参数,在使⽤this声明其他的构造器的时候,必须在第⼀⾏调⽤类上的构造器。
伴生对象(重点)
如果类和object在⼀个scala源⽂件中,则称为object User 是class User的伴⽣对象,使⽤伴⽣对象可以⽅
便的创建类的对象,只需要覆盖对应的apply⽅法,如下:
class User(var id:Int,var name:String,var age:Int) {
}
object User{
def apply(id: Int, name: String, age: Int): User = new User(id, name, age)
}
伴生对象的单例类和类的名称必须一致,创建对象的方法如下:(使用apply方法时apply可以省略)
var user=User.apply(1,"aaa",18) //等价于 new User(1,"aaa",18) 或者直接 User(1,"aaa",18)
可以理解apply是一个工厂方法,该方法的作用就是生产类的对象
使用unapply方法可以将对象中的一些属性反解出来
def unapply(u: User): Option[(Int, String, Int)] = {
Some((u.id,u.name,u.age))
}
var user=User(1,"aaa",18) //等价于 new User(1,"aaa",18)
var User(id,name,age)=user
print(id+"\t"+name+"\t"+age)
注意⼀个伴⽣对象中只能有⼀个unapply⽅法,这不同于apply⽅法,因为apply⽅法可以有多个。
抽象类 abstract
抽象类中可以有已经实现的方法和未实现的方法
abstract class Animal(var name:String) {
def eat():Unit={
print("animal can eat")
}
def sleep():String
}
接口|特质 trait(scala)
trait speakable {
def speak():Unit
}
trait flyable{
def fly():Unit
}
继承和实现(重点)
创建一个Dog对象继承Animal抽象类,实现trait中的抽象方法
class Dog(name:String) extends Animal (name:String) with speakable {
override def sleep(): String = {
s"${name}\t在睡觉"
}
override def speak(): Unit = {
print("汪 汪 汪")
}
override def eat(): Unit = {
print(s"${name}\t啃骨头")
}
}
object Dog{
def apply(name: String): Dog = new Dog(name)
}
var dog=Dog("大黄")
dog.eat()
dog.speak()
print(dog.sleep())
trait的动态植入
假如说现在有⼀个Bird继承⾃Animal,在使⽤的时候会发现该类需要具备Flyable的功能:
class Bird(name:String) extends Animal(name :String) {
override def sleep(): String = {
"bird is sleeping"
}
}
var bird=new Brid("小鸟") with flyable{
override def fly(): Unit = {
println(name + "\t飞")
}
}
bird.fly()
在覆盖有实现的⽅法必须添加 overwrite
⼀个类只能继承⼀个类with多个trait例如:Class A extends B with C with D{}
如果只是单一实现一个特质或抽象类必须使用 extends
self
等价于this关键字,在this出现混淆的时候使用self给关键字起别名
class User {
self:User => //:User可以省略
var id:Int = _
var name:String = _
var age:Int = _
def this( id:Int, name:String, age:Int){
this()
self.id=id
self.name=name
self.age=age
}
}
Trait强制混合
以下案例就是要求所有Flyable的⼦类必须实现Bird接⼝。
trait Flyable{
this:Bird => //可以将 该this看做成Bird类
def fly():Unit={
println(this.name+" 可以⻜!")
}
}
trait Bird{
def name:String
}
class FlyFish(n:String) extends Flyable with Bird {
override def name= this.n
}
case class(重点)
case class就像常规类,case class 用于对不可变的数据进行建模
case class UserCase(id:Int,name:String) //样例类可以没有方法体的实现
val userCase1 = new UserCase(1,"aaa")
val userCase2 = UserCase(2,"bbb")
println(userCase1)
println(userCase2)
UserCase(1,aaa)
UserCase(2,bbb)
样例类创建的对象 == 比较时比较的是内容,其次样例类中的所有属性是只读,赋值一次后不可更改,通常用于作数据建模。
val userCase2 = UserCase(2,"bbb")
var userCase3 = UserCase(2,"bbb")
println(userCase2 == userCase3) //true
可以简单的使⽤copy来实现两个对象间的值得传递
var userCase3 = UserCase(2,"bbb")
var userCase4=userCase3.copy(userCase3.id,userCase3.name)
println(userCase4)
case class之间不存在继承关系。