一、Scala简介、类和对象、简单语法

192 阅读7分钟

为什么学习Scala?

因为需要学习Spark,而Spark框架开发使用最好的语言就是Scala,虽然Java也可以进行Spark的开发,但是不如Scala效率高,并且市面上大家都是使用Scala开发,遇到问题方便交流学习。并且Scala是在JVM上运行的,可以与Java代码互相操作。

因为之前一直使用Java语言作为主要开发语言,学习起Scala感觉不太适应,因为Scala极简的语法和很多固定操作需要掌握,固定操作比_,方法的简洁写法等等,一个功能Java语言需要100行实现,Scala可能只需要十几行就可以完成,极简的方式导致可读性比较低。

个人觉得应对这些困难的方式就是刻意练习,把几种常用的比较难理解的固定写法多练多记。

唠唠叨叨,接下来开始学习!!!

一、Scala简介

Scala是一种针对JVM将面向对象函数式编程技术组合在一起的编程语言。Scala既是面向对象,又是面向函数语言。那么什么是面向对象,什么是面向函数呢?有什么特点,有什么区别呢?

面向对象:什么是对象?就是把一个小功能拆解成一块,比如一个计算器功能可以拆解为普通计算器对象,多功能计算器对象等;或者说对象就是某一类食物的具体展现。

想要创建对象就需要有一个类,比如人类这个类,那么对象就是一个具体的人。

面向对象的思想就是把人类这个大的类的一些共同的行为抽象出来,然后创建不同的具体对象,实现不同的行为。 类是对象的抽象,对象是类的具体实现。

面向函数:个人理解函数式编程相对于面向对象编程,更注重的是函数的运用,函数是程序中的单位。

极简原则:不用写的东西都可以省略

Scala的六大特性:

  1. Java可以和Scala混编
  2. 类型推测 :定义变量的时候如果不指定具体的类型,赋值之后,Scala会根据变量和所赋的值自动推断出变量的类型。
  3. 并发式和分布式 Scala1.6之前使用Actor通信模型,实现通信;1.6之后使用netty实现通信。不必考虑锁的问题。
  4. Trait: 特质、特征:相当于Java中的抽象类和接口的组合体,可以定义变量和常量,可以写含有方法体的方法,也可以写没有方法体的方法(抽象方法)
  5. 模式匹配:类比于Java中的switch case,但是要比Java中的switch case功能多。可以对不同类型的数据进行匹配,并且可以进行值和类型的匹配。
  6. 高阶函数:这一部分个人认为这一部分是Scala区别于Java最重要的部分,说的简单点就是方法可以赋值给一个变量,方法可以作为另一个方法的参数等等,也就是说方法可以像Java中的一个对象去操作,方法也可以是被当作一个对象。

二、Scala基础

1、数据类型

Byte、Short、Int、Long、Float、Double Char String Boolean 这些数据类型和java中的数据类型一样

需要特别指出的特有类型:

  • Unit 表示无值,和其他语言中的void等同
  • Null 空值或者空引用
  • Nothing 所有其他类型的子类型,表示没有值;用于类型推断不出来的时候作为范型
val list:List[Nothing]=List()
// 这个时候创建list的时候没有指定具体的类型,类型推断不出来,就认定为Nothing类型
  • Any 所有类型的超类,任何实例都属于Any类型,但是Any类型是Object类的子类,算得上是一人之下,万人之上
  • AnyRef 所有引用类型的超类,比如NUll类型
  • AnyVal 所有值类型的超类 比如Int,Double类型

None: Option的两个子类之一,另一个是some,用于安全的函数返回值。避免出现空指针异常,会返回None

Nil :长度为0的List

image.png

2、变量与常量的声明

(1)

var 用于定义变量

var a=2
a =3
//变量定义好之后也可以重新赋值

val 用于定义常量,常量定义好之后不能再赋值。相当于Java中的final

val a=2
a =3  //这里会报错
//变量定义好之后也可以重新赋值

(2)定义变量或者常量的时候,可以写上类型,一般都不写,Scala可以进行类型推断,比如

val a=2
val a:Int=2
//上边两种方式都可以

(3)表达式赋值

//当表达式中返回的值类型都一样的时候,类型推断出是具体的类型
val y:Int=if(a>0) 1 else -1
//当表达式中返回的值类型不一样的时候,类型推断的就是Any类型,任意类型
val x:Any=if(a>0) 1 else "haha"
val value2: Any = if(a>0) new Person("haha")
//当表达式中含有未知数据的时候,类型推断的是AnyVal类型,值类型。这是根据已知的类型推断出来的
var value1: AnyVal =if (a>0) 1
//value1现在被推断成Anyval类型的话,那么再给value1变量赋值引用类型会怎样呢?
value1=new Person("xiaoxin") //这里会报错,因为person是引用类型,不能复制给AnyVal类型的变量。
//这个时候指定value1是Any类型,就没有问题了

var value1: Any =if (a>0) 1
//value1现在被推断成Anyval类型的话,那么再给value1变量赋值引用类型会怎样呢?
value1=new Person("xiaoxin") //这里会报错,因为person是引用类型,不能复制给AnyVal类型的变量。

建议使用val,因为便于内存回收

三、Scala的类和对象

1、类 class

Scala中的类和Java中的类概念相同,这里主要注意几点区别:

类的定义:

// class Person(val name:String){ 参数前边使用val,表示为私有的,外界不可以访问
// class Person(var name:String){ 参数前边使用var,表示为可见的,等同于public
//类属性自带gatter、setter方法,也就是下边name和age都有自己的getter、setter方法
class Person(name:String){ //这里就是Person的默认构造函数
  var gender=2
  
  println("hhah")// 直接写代码块,相当于静态代码块
  
  def this(xname:String,age:Int) { //构造函数重载一定要复写默认构造函数,使用this关键字
    this(xname)
    gender=age
  }
}

val p=new Person("haha")

2、对象 object

被Object修饰的类,这里称为对象,类似于Java中的单例,工具类;object中定义的全部都是静态的。 使用的时候也可以传参,传参默认调用的是内部的apply方法。apply可以被重载。

class Person(name:String){
  var gender=2
  def this(xname:String,age:Int) {
    this(xname)
    gender=age
    ScalaGrammar(name)
    ScalaGrammar("ah",9)  //默认调用apply方法
  }
}

object ScalaGrammar { //相当于是Java中的单例

  def main(args: Array[String]): Unit = {

  }

  def apply(name:String)={

  }
  def apply(name:String,age:Int)={

  }
}

3、伴生对象以及伴生类

当一个文件中的对象名和类名相同的时候,互为伴生,可以相互访问对方内部的私有变量。

object ScalaGrammar {

  val yyyname="ooo"
  def main(args: Array[String]): Unit = {
    val grammar = new ScalaGrammar()
    grammar.xxxname
  }
  
}

class ScalaGrammar(){
  val xxxname="xixix"
  def yy(): String ={
    ScalaGrammar.yyyname
  }
}

四、条件、循环

0、to 和until的用法

to和until都是获取一段整数范围,until与to的区别在于不取最后一个数,左闭右开。

1 to 10
等同于
1.to(10)
获取的是1-10的整数

1.to(10,3) 步长概念,跨三个数取一个数 14710

1 until (10)    1-9

他们的底层都是range

range(1,10)
range(1,10,3) 步长

range和until一样,都是左闭右开

1、if else

条件查询写法和Java很像。

if (age>10){
  print("111")
}else if(age>20){
  print("222")
}else{
  print("333")
}

2、循环

(1)、for

for语句中的特定写法,<- 让我想起了大学学c语言,指针好像就是使用这个,当时对这个很抵触,现在看到依然很恐惧。不过它只是个固定写法,记住就行了。

这里最重要的就是记住<-的固定写法,类似于in的用法。

for(i <- 0.to(10)){
  println(i)
}

val arr=Array[Int](1,2,3,4,2,3,4)
for(i<- arr){
  println(i)
}

(2)、多层for循环

多层循环可以使用卸载一个for中,使用隔开,这样构成多层for循环

val arr=Array[Int](1,2,3,4,2,3,4)
var count =1
for(i<- arr){
  for(j<-0.to(20)){
    println(i+j)
    count+=1
  }
}
//等同于
for(i<-arr;j<-0.to(20)){
  println(i+j)
  count+=1
}

scala中年不能使用i++,i--,只能使用i+=1;

for循环中有条件语句,也可以写到for语句中

val arr=Array[Int](1,2,3,4,2,3,4)
for(i<- arr){
  if(i%2==0){
    if(i>4) {
      print(i)
    }
  }
}
//等同于
for(i<-arr;if(i%2==0);if(i>4)){
  println(i)
}

yield关键字,将for循环的结果转化成一个集合

val ints: Array[Int] = for (i <- arr; if (i % 2 == 0); if (i > 4)) yield i

(3)、while do-while循环

while循环

val arr=Array[Int](1,2,3,4,2,3,4,6,8,9,10)

val ints: Array[Int] = for (i <- arr; if (i % 2 == 0); if (i > 4)) yield i

val iterator = ints.iterator
while(iterator.hasNext){
  println(iterator.next())
}

do-while循环:先执行语句,再循环

val arr=Array[Int](1,2,3,4,2,3,4)

val ints: Array[Int] = for (i <- arr; if (i % 2 == 0); if (i > 4)) yield i

val iterator = ints.iterator
do{
  println(iterator.hasNext)  //当第一次进来取不到值的时候会报错
}while(iterator.hasNext)