Scala的函数和类

函数

函数声明

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之间不存在继承关系。

猜你喜欢

转载自blog.csdn.net/origin_cx/article/details/104338897