1.var,val和def三个关键字之间的区别?
-
Scala声明变量有两种方式,一个用val,一个用var。
val / var 变量名 : 变量类型 = 变量值。
val定义的值是不可变的,它不是一个常量,是不可变量,或称之为只读变量。
var 定义变量,val定义不可变量(val是java的final不可变变量,var是java的普通变量),变量和常量类型可以省略不写,自动推断;在main函数里,val和var仅声明变量;在class类定义里,val和var是先声明field存储空间,然后分别为他们定了同名的方法;
var 变量定义了 同名方法(类似getter) 来获取它的变量值,同时提供了修改变量值的方法(类似于setter)
var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态是可以改变的
在应用过程中,尽可能地使用不可变变量。变量类型可以省略,解析器会根据值进行推断。val和var声明变量时都必须初始化。
用def定义的成员变量,不具备setter和getter方法
def 定义函数时,每一次重新获得一个函数
def 函数名(参数名1: 参数类型1, 参数名2: 参数类型2) : 返回类型 = {函数体}
def 和 val的关系是call-by-name和call-by-value的关系,def对应的是by-name,val对应的是by-value
其中:call-by-value是在调用函数之前计算;call-by-name是在需要时计算
还有一个lazy val(惰性val)声明,当需要计算时才使用,避免重复计算
-
trait(特质)和abstract class(抽象类)的区别?
trait:
Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。
一般情况下Scala的类可以继承多个Trait,从结果来看是实现了多重继承。Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
特质是一些字段和行为的集合,可以扩展或混入(mixin)类中,通过with关键字,一个类可以扩展多个特质。
1.优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
2.如果需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。
abstract class:
抽象类定义了一些方法但没有实现他们。取而代之的是有扩展抽象类的子类定义这些方法。不能创建抽象类的实例。
在Scala中重写一个非抽象方法必须使用override修饰符。调用超类的方法就如Java一样,使用super关键字。
-
object和class的区别?
object:
Scala中没有静态修饰符,static,在object下的成员全部都是静态的,如果在类中声明了与该类相同的名字的object则该object是该类的“半生对象”。
所以在scala中用object来实现这些功能,直接用对象名调用的方法都是采用这种实现方式,例如Array.toString。对象的构造器在第一次使用的时候会被调用,如果一个对象从未被使用,那么他的构造器也不会被执行;对象本质上拥有类(scala中)的所有特性,除此之外,object还可以一扩展类以及一个或者多个特质,object不能提供构造器参数,object必须是无参的,main方法都必须在object中被调用,提供程序的主入口。
可以理解把类中的static集中放到了object对象中,伴生对象和类文件必须是同一个源文件,可以用伴生对象做一些初始化的操作。
class:
和java中的class类似。在Scala声明private变量会Scala编译器会自动生成get,set,在Scala中变量是需要初始化的,如果不声明private默认是public的
trait:
在java中可以通过interface实现多重继承,在Scala中可以通过特征(trait)实现多重继承,不过与java不同的是,
它可以定义自己的属性和实现方法体,在没有自己的实现方法体时和java interface是等价的,在Scala中也是一般只能继承一个父类,可以通过多个with进行多重继承。
-
伴生对象是什么?
在Scala中,伴生对象就是与类名相同的对象。并且所在的类被称为伴生类。
伴生对象可以访问类中的私有量,类也可以访问伴生对象中的私有方法,类似于Java类中的静态方法。伴生对象必须和其对应的类定义在相同的源文件。
-
Scala类型系统中Nil, Null, None, Nothing四个类型的区别?
Null是一个trait(特质),是所有引用类型AnyRef的一个子类型,null是Null唯一的实例。
Nothing也是一个trait(特质),是所有类型Any(包括值类型和引用类型)的子类型,它不在有子类型,它也没有实例,实际上为了一个方法抛出异常,通常会设置一个默认返回类型。
Nil代表一个List空类型,等同List[Nothing]
None是Option monad的空标识 -
Unit类型是什么?
表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
-
Option类型的定义和使用场景?
Scala Option(选项)类型用来表示一个值是可选的(有值或无值)。
Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None 。
Option 有两个子类别,一个是 Some,一个是 None,当他回传 Some 的时候,代表这个函式返回一个 String,可以通过 get() 这个函式拿到那个 String,如果返回的是 None,则代表没有字符串。
序号 方法及描述 1 def get: A获取可选值 2 def isEmpty: Boolean检测可选类型值是否为 None,是的话返回 true,否则返回 false 3 def productArity: Int返回元素个数, A(x_1, …, x_k), 返回 k 4 def productElement(n: Int): Any获取指定的可选项,以 0 为起始。即 A(x_1, …, x_k), 返回 x_(n+1) , 0 < n < k. 5 def exists(p: (A) => Boolean): Boolean如果可选项中指定条件的元素存在且不为 None 返回 true,否则返回 false。 6 **def filter(p: (A) => Boolean): Option[A]**如果选项包含有值,而且传递给 filter 的条件函数返回 true, filter 会返回 Some 实例。 否则,返回值为 None 。 7 **def filterNot(p: (A) => Boolean): Option[A]**如果选项包含有值,而且传递给 filter 的条件函数返回 false, filter 会返回 Some 实例。 否则,返回值为 None 。 8 def getOrElse[B >: A](default: => B): B
如果选项包含有值,则传递给函数 f 处理后返回,否则返回 None9 def foreach[U](f: (A) => U): Unit
如果选项包含有值,则将每个值传递给函数 f, 否则不处理。10 def getOrElse[B >: A](default: => B): B
如果选项包含有值,返回选项值,否则返回设定的默认值。11 def isDefined: Boolean如果可选值是 Some 的实例返回 true,否则返回 false。 12 def iterator: Iterator[A]
如果选项包含有值,迭代出可选值。如果可选值为空则返回空迭代器。13 **def map[B](f: (A) => B): Option[B]**
如果选项包含有值, 返回由函数 f 处理后的 Some,否则返回 None14 def orElse[B >: A](alternative: => Option[B]): Option[B]
如果一个 Option 是 None , orElse 方法会返回传名参数的值,否则,就直接返回这个 Option。15 def orNull如果选项包含有值返回选项值,否则返回 null。 -
解释隐示参数的优先权
在函数或者方法中,定义一个用implicit修饰的参数,此时Scala会在作用域内尝试寻找一个指定类型的,用implicit修饰的对象,即隐式值,并注入参数。
在Scala中implicit的功能很强大。当编译器寻找implicits时,如果不注意隐式参数的优先权,可能会引起意外的错误。因此编译器会按顺序查找隐式关键字。
顺序如下:
(1)当前类声明的implicits ;
(2)导入包中的 implicits;
(3)外部域(声明在外部域的implicts);
(4)inheritance
(5)package object
(6)implicit scope like companion objects -
什么是函数柯里化?
高阶函数(函数的返回类型是函数)的简化,是高阶函数的一种定义方式。
def fun3(a: Int, b: Int)(c: Int, d: Int): Int = { a + b + c + d } println(fun3(1,2)(2,3))
-
什么是高阶函数?
就是操作其他函数的函数
1.函数的参数是函数,
2.或者函数的返回类型是函数(必须显示的写出方法的返回值类型),
3.或者函数的参数和函数的返回类型是函数的函数。
-
yield如何工作?
yield用于循环迭代中生成新值,yield是comprehensions的一部分,是多个操作(foreach, map, flatMap, filter or withFilter)的composition语法糖。comprehension(推导式)是若干个操作组成的替代语法。如果不用yield关键字,comprehension(推导式)可以被forech操作替代,或者被map/flatMap,filter代替。
-
偏应用函数和偏函数的区别
偏函数:
是一个数学概念它不是"函数"的一种, 它跟函数是平行的概念。
Scala中的Partia Function是一个Trait,其的类型为PartialFunction[A,B],其中接收一个类型为A的参数,返回一个类型为B的结果。偏函数内部有一些方法,比如isDefinedAt、OrElse、 andThen、applyOrElse等等。
偏应用函数:
偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供一部分,或不提供所需参数。是一个逻辑上概念。
偏应用函数类似于柯里化。
-
case class (样本类)是什么?
用于描述不可变的值对象(Value Object
)。
Scala的case Class就是在普通的类定义前加case这个关键字,然后可以对这些类来模式匹配。case Class支持模式匹配:
样本类JsBoolean
是一个持有Boolean
值的JSON
对象
判断一个对象是否是某个类的对象,跟Java一样可以使用isInstanceOf。
样本类的特点:
- 隐式地声明字段为
val
; - 自动混入特质
ProductN
; - 自动地生成
equals, canEqual, hashCode, toString, copy
等方法; - 伴生对象中自动生成
apply, unapply
方法。
不过,样本类扩大了类的空间及其对象的大小。
样本类是一种特殊的类,它经过优化以被用于模式匹配。
一个模式匹配包含了一系列备选项,每个都开始于关键字case。每个备选项都包含了一个模式及一到多个表达式,在模式匹配过程中被计算。
package com.stu.array
object CaseClass {
def main(args: Array[String]): Unit = {
println(cal("+"))
prtList(List(0, 1))
println(prtType("abc"))
println(prtType(Map(1 -> 1)))
}
def cal(exp: String): Int = {
val add = "+"
val result = 1
exp match {
case "+" => result + 2 //常量模式仅仅匹配自身
case "-" => result - 2
case "*" => result * 2
case "/" => result / 2
case add => result + 2 //变量模式可以匹配任意对象
case _ => result //通配模式匹配任意对象
}
}
//序列模式
def prtList(list: List[Int]) = list match {
case List(0, _, _) => println("this is a list") //序列模式,可以匹配List或者Array
case List(1, _*) => println("this is a list, too") //匹配一个不指定长度的序列
case _ => println("other")
}
//元组模式
def prtTuple(tup: Any) = tup match {
case (0, _, _) => println("this is a tuple") //元组模式
case _ => println("other")
}
//类型模式,可以用在类型测试和类型转换
def prtType(x: Any) = x match {
case s: String => s.length
case m: Map[_, _] => m.size
case _ => 1
}
}