Featured image of post scala

scala

大数据入门语言,不学java也能学。因为米哈游不要了所以暂时不学了

Scala

image-20230304222803377
image-20230304222803377

其中Unit表示AnyVal中的空值而Null表示AnyRef中的空值。Scala中的绝大部分内容都和其他语言类似,差距比较大的是三种空值:

image-20230304224731105
image-20230304224731105

Nothing(异常)作为函数返回值其实是没有意义的,但是由于其可以作为所有类型的父类,因此可以用于丢出异常

def m2(n: Int): Int = {
    if(n == 0)
    	throw new NullPointerException
    else
    	return n
}

而Unit在全局只有一个实例。

由于scala包含了很多java的元素,其中与java的类型转换也有较大的差别。java中类型转换byte-short-int/char-int

由于scala是强类型语言,不同类型之间无法相互转换,因此就需要使用强制类型转换进行:

char c = 'a'
short c2 = c.toShort;
//直接 c = (short)c 会报错

一个要注意的一点是,虽然对于字符串我们可以拼接各种各样的基本数据类型,但是对于short、char这些类型的计算操作是需要我们乖乖转化为int的

scala在比较运算符中有一点的要注意的是,java中引用类型的的==,比较的是引用地址而在scala中比较的是值。(使用.eq来比较引用地址)

scala的位运算与其他语言基本一致,需要注意的是移动运算符«»为有符号的移动运算符,而«<»>是无符号的移动运算符。scala的运算符底层是方法所以可以通过如下方法调用

var n1 : Int = 12
println(n1.+(2))

scala中的分支语句可以像函数一样具有返回值,所以就可以写作:

val res : Any  = if (a < 1){
    println(a)
}else if(a > 1){
	"6"
}else{
    6
}
val res2 = if(a<1) "<" else ">" 

在下面的这种写法下其实非常接近三元表达式。

scala的for循环类似python。

for(i <- 1.to(3))
for(i <- 1 to 3)
for(i <- new Range(1,10,3))
for(i <- 1.until(3))
for(i <- 1 until 3)

如果将for和if结合一下就可以得到混沌的循环守卫(scala没有continue)

for(i<-1.to(5) if i!= 2){
    println(i);
}

虽然有很多可有可无的东西,但是其多层循环设计的非常合理:

for(i<- 1 to 4;j <- 1 to 5)

从前面的代码中可以看到scala可以获取if语句的返回值,同理也可以使用for循环的返回值,但是for循环默认返回的值是一个空的unit,若想获得for的返回值,需要将其变为一个list或array,这里需要使用到yield关键字

val b = for(i <- 1 to 10) yield i

由于相较于for循环,while非常的鸡肋,所以不如使用for。

对于scala,是没有break的,所以需要使用一个break类进行

import scala.util.control.Breaks._ //引入所有的
Breaks.breakable(
	for(i<-0 until 5){
        if (i == 3)
        	Breaks.break()
        println(i)
    }
)

scala除了面向对象以外,它还具有函数式编程的特性,函数的设计方式和python大同小异

def f1(str1: String*)
def f2(str1: String, str2: String*)
def f3(str1: String = "")
def f4(str1: String, int2: Int)
f4(int2=22,str1="")

scala的返回值和函数设计则是参考了多种语言的特性

image-20230305165712388
image-20230305165712388

其他的东西可能并不算太大的重点,核心的一个是lambda匿名函数的定义和使用:

val fun = (name : String) => {println(name)}

def f(func: String => Unit) : Unit = {
    func("666")
}

总体来看,使用lambda函数的例子:

val add = (a: Int, b: Int) => a + b
val minus = (a: Int, b: Int) => a - b
def dualFunc(func:(Int, Int) => Int): Int = {
    func(1, 2)
}

scala的函数式过于混沌:

def arrayOperation(array: Array[Int], op: Int=>Int): Array[Int] = {
    for (elem <- array) yield op(elem)
}

看个练习:

def func(a:Int) : String => (Char => Boolean) = {
    def f1(b: String): Char => Boolean= {
        def f2(c: Char): Boolean = {
            if (a == 0 && b == "" && c == '0') false else true
        }
        f2
    }
    f1
}
println(func(0)("")('0'))
def func(a: Int): String => (Char => Boolean) = {
    b => c => if (a == 0 && b == "" && c == '0') false else true
}
//柯里化
def func(a: Int)(b: String)(c: Char): Boolean = {
    if (a == 0 && b == "" && c == '0') false else true
}

scala对闭包有着较大的支持。同时也有函数柯里化的操作

scala还有一个比较有趣的东西叫做控制抽象,里面主要包含了传值参数和传名参数。其中传值参数很好理解:

f1(f2())

但是传名参数就很抽象了

def f2(a: => Int): Unit = {
    println(a)
}

上面f2的参数是一个返回值为Int的代码块。每次调用a都会执行代码块中的内容。

最后再来看一个包含了上面所有内容的代码块

def myWhile(condition: => Boolean): ={
    def doLoop(op: =>Unit):Unit = {
        if(condition){
            op
            myWhile(condition)(op)
        }
    }
    doLoop _
}
n=10
myWhile(n>=1){
    println(n)
    n-=1
}
//柯里化
def myWhile(condition: => Boolean)(op: =>Unit):Unit = {
    if(condition){
        op
        myWhile(condition)(op)
    }
}

对于python而言,惰性运算是内部存在定义的,只有需要取值时才会进行运算和操纵。而对于scala,只需要使用lazy关键字进行定义即可。

scala使用package定义包,其中可以直接使用包对象,包对象的定义必须和包定义在同一级目录下

image-20230305223417696
image-20230305223417696

scala的类拥有访问权限等内容,但是同样是老东西了。对于类的构造,只需要在定义类的时候添加形参即可,但是这只不过是主构造器,为了使类构造器可以实现重载等功能,可以使用this作为函数名设计一系列辅助构造器

Licensed under CC BY-NC-SA 4.0