scala变量

声明变量

普通变量

  1. var a: String = "Foo"
  2. var b: Int = 20

数组

  1. var c: Array[String] = Array("a", "b")
  2. var d = Array(1,2)
  3. var e = new Array[Int](2)
  4. e(0) = 100

元组

  1. var d = (1,2)

scala字符串处理

定义字符串

var a = "hello"
var b: String = "scala"

字符串拼接

var a = "hello" + "scala"

值插入

var a = "scala"
var b = s"hello $a"
var c = s"${a + b}"

判断是否相同

var a = "hello"
var b = "hello scala"
a.equals(b) // false
a.equalsIgnoreCase("Hello") //true

判断是否包含

var a = "hello scala"
a.contains("scala")     // true

判断开头和结尾

var a = "hello scala"
var b = a.startsWith("hello") // true
var c = a.endsWith("scala") // true

索引某个子串

var a = "hello scala"
println(a.indexOf("s")) // 6
println(a.lastIndexOf("a")) // 10

截取子串

var a = "hello scala"
var b = a.substring(6) // scala
var c = a.substring(0,5) // hello

字符串替换

var a = "hello scala"
var b = a.replace("a", "o") // hello scolo

字符串分割

var a = "hello scala"
var b: Array[String] = a.split(" ")

scala数组

定义数组变量

var a: Array[Int] = new Array[Int](3)
var b = Array("a", "b", "c")
var c = Array.range(1,6) //1,2,3,4,5
var d = Array.range(1,6,2) //1,3,5

访问和修改数组元素

var a = new Array[Int](3)
a(0) = 100
println(a(0))
a(1) = 200
a(2) = 300

追加元素

在scala中,Array是immutable(不可变)的,追加元素不会改变原数组,而是返回一个新的数组

val a = Array(1,2,3)
val b = a :+ 10 // 1,2,3,10
val c = 100 +: a // 100,1,2,3

遍历数组

var a = Array.range(1,6)
for(item <- a){
    println(item)
}

mkString

var a = Array.range(1,6)
a.mkString("[", ",", "]") // [1,2,3,4,5]
a.mkString(",") //1,2,3,4,5
a.mkString // 12345

算子

map

var a = Array(1,2,3)
a.map(_ * 2)  // 2,4,6

filter

var b = Array(1,2,3,4,5,6)
b.filter(_ % 2 == 0) // 2,4,6

flatMap

var c = Array("hello world", "hello java", "hello scala")
c.flatMap(_.split(" ")) // hello,world,hello,java,hello,scala

reduce

var d = Array(1,2,3,4,5)
d.reduce(_ + _) // 15
d.reduceLeft(_ - _) // -13
d.reduceRight(_ - _) // 3

reduceLeft计算逻辑(同reduce)

1 - 2 = -1
(-1) - 3 = -4
(-4) - 4 = -8
(-8) - 5 = -13

reduceRight计算逻辑:

4 - 5 = -1
3 - (-1) = 4
2 - 4 = -2
1 - (-2) = 3

sum

var e = Array.range(1,6)
e.sum //15
e.max //5
e.min //1

scala列表

定义列表

val list = List(1,2,3)
val list2: List[String] = List()
val list3 = List("A", "B", "C")
val list4 = List.range(1, 5) // 1,2,3,4
val list5 = List.range(1, 5, 2) // 1,3

scala中里的列表List是不可变的(immutable), 意味着你无法为List添加、修改、删除元素。如果你想基于现有的List进行如上操作,都会返回一个新的List

访问列表

val list = List.range(1,6) // 1,2,3,4,5
println(list(2)) //3

修改部分元素

val list = List.range(1,6)
val list2 = list.update(1, 100)  // 1,100,2,3,4,5

列表属性

val list = List(1,2,3)
list.isEmpty // false
list.size // 3
list.head // 1
list.tail // [2,3]

截取子列表

val list = List.range(1, 6)
list.slice(1,3) // 2,3

取前几个元素

val list = List.range(1, 6)
list.take(3) // 1,2,3

取后几个元素

val list = List.range(1, 6)
list.takeRight(3) // 3,4,5

在列表尾部添加元素

val list = List(1,2,3)
val list2 = list :+ 5 // 1,2,3,5

在列表首部添加元素

val list = List(1,2,3)
val list2 = 0 +: list // 0,1,2,3

连接两个列表

val l1 = List.range(1,3)
val l2 = List.range(5,8)
val l3 = l1 ::: l2 //1,2,5,6,7

算子

map

var a = List(1,2,3)
a.map(_ * 2)  // 2,4,6

filter

var b = List(1,2,3,4,5,6)
b.filter(_ % 2 == 0) // 2,4,6

flatMap

var c = List("hello world", "hello java", "hello scala")
c.flatMap(_.split(" ")) // hello,world,hello,java,hello,scala

reduce

var d = List(1,2,3,4,5)
d.reduce(_ + _) // 15
d.reduceLeft(_ - _) // -13
d.reduceRight(_ - _) // 3

reduceLeft计算逻辑(同reduce)

1 - 2 = -1
(-1) - 3 = -4
(-4) - 4 = -8
(-8) - 5 = -13

reduceRight计算逻辑:

4 - 5 = -1
3 - (-1) = 4
2 - 4 = -2
1 - (-2) = 3

sum

var e = List.range(1,6)
e.sum //15
e.max //5
e.min //1

其它


def append[T](list: List[T], item: T): List[T] = {
    list :+ item
}

def preAppend[T](list: List[T], item: T): List[T] = {
    item +: list
}

def concat[T](lists: List[T]*): List[T] = {
    var r = List[T]()
    for (item <- lists) {
      r = r ::: item
    }
    r
}

def insert[T](list: List[T], item: T, i: Int): List[T] = {
    concat(list.slice(0, i), List(item), list.slice(i, list.size))
}

元组

元组可以存放不同数据类型的数据,最多支持22个

定义元组

val t1 = (1,2,"a")

访问元素

val t1 = (1,2,"a")
println(t1._1)
println(t1._2)
println(t1._3)

集合

定义集合

var a = Set("a", "b")

判断包含

var a = Set("a", "b")
println(a.contains("a"))

映射

定义映射

var map = Map("a" => 1, "b" => 2)

访问元素

var map = Map("a" => 1, "b" => 2)
println(map("a"))

遍历

var map = Map("a" => 1, "b" => 2)
for((key, value) <- map){
  println(key, value)
}

函数

scala注重函数式编程,所以函数在scala中占主导地位,很多地方都会用到函数

定义一个函数

def foo() = {
    println("hello foo")
}

调用foo函数

foo() // hello foo

带参数的函数

def sum10(a: Int) = {
    println(a + 10)
}
sum10(1) // 11

有返回值的函数

def sum(a:Int, b:Int): Int = {
    return a + b
}
sum(10,20) // 30

具名参数

所谓具名参数,就是给函数传递参数的时候给参数命个名,传递具名参数有一个好处是可以混淆参数的位置

def sum(a:Int, b:Int): Int = {
    return a + b
}
sum(a= 10, b= 20) // 30
sum(b= 20, c= 10) // 30

默认值参数

我们可以给函数的参数设置默认值,当不传递参数的时候,我们就会用默认值作为参数的值

def hello(greet: String = "hello", name: String) = {
    println(greet + " " + name)
}

hello("welcome", "john") // welcome john
hello(name="bob") // hello bob

我们不能按如下方式调用hello方法

hello("bob")

那是因为带有默认值的参数放在了第一位

如果你想按如上方式调用hello方法,必须把name参数放到第一位,把带有默认值的参数放在后面。

def hello2(name: String, greet:String="hello") = {
    println(greet + " " + name)
}

调用

hello2("bob")

可变参数

1.当函数可以接受一个或多个不定的参数时,我们可以用可变参数

2.可变参数必须定义参数列表末尾

def sum(a: Int,nums:Int*): Int = {
    return a + nums.sum
}
sum(1,2,3) // 6

传递可变参数

def sum(nums: Int*): Int = {
    return nums.sum
}

var ns = Array.range(1, 6)
println(sum(ns: _*))

高级函数

函数作为参数

def dealArray(arr: Array[Int], fn: Int => Int): Array[Int] = {
    var rst = new Array[Int](arr.length)
    var i = 0
    arr.foreach(one => {
      rst(i) = fn(one)
      i += 1
    })
    rst
}

调用

dealArray(Array.range(1, 6), (x:Int) => x * 2)

函数作为返回值

def add(x: Int): Int => Int = (y: Int) => { x + y }

调用

var a = add(10)
println(a(1)) // 11
println(a(2)) // 12

var b = add(20)
println(b(1)) // 21
println(b(2)) // 22

闭包

闭包是一个函数,这个函数依赖于函数外部定义的一个或多个局部变量。

def makeAdd(more: Int) = (x: Int) => x + more  //这里省略了返回值定义

makeAdd方法的返回值就是一个闭包(函数),该闭包依赖函数外部定义的局部变量more,当more值发生变化时,闭包里的more也会跟随变化。

var s1 = makeAdd(1) 
s1(100) // 101
s1(200) // 201

var s2 = makeAdd(10)
s2(100) // 110
s2(200) // 210

定义一个类

class A {

}

构造函数

构造函数分为两种:主构造函数和辅助构造函数

主构造函数直接定义在类名后面,每个类都有主构造函数,主构造函数的参数直接放置类名后面,与类名同行
辅助构造函数自定义,使用def this关键字,而且必须调用主构造函数,或者其他的辅助构造函数

主构造函数

class Person(var name: String, val age:Int) {

}

测试

val p = new Person("john", 20)
println(p.name) // john
println(p.age) // 20
p.name = "helo"
println(p.name) // helo

1.主构造函数的用var声明的属性,scala会自动为其生成setter和getter方法,意味着你可以通过对象来修改它

2.主构造函数中用val声明的属性,scala只会为其生成getter方法,这种属性一旦初始化,无法修改,但是允许访问

辅助构造函数

使用def this定义辅助构造函数,且参数列表中的参数不能使用var和val声明

class Person(var name: String, val age:Int) {

  var gender:String = "male"

  def this(name: String, age: Int, gender:String) {
    this(name, age)
    this.gender = gender
  }
}

测试

val p = new Person("lily", 20, "female")
println(p.gender) // female
p.gender = "male"
println(p.gender) // male

可见性

可见性名称 关键字 描述
public 无关键字 任何作用域内均能访问公有成员或公有类型,public 可见性无视所有限制
protected protected 受保护(protected)成员对本类型、继承类型以及嵌套类型可见。而受保护的类型则只对相同包内或子包内的某些类型可见
private private 私有(private)成员只对本类型和嵌套类型可见,而且可以访问私有成员的类型必须位于相同包内
作用域内受保护 protected[scope] 只能在某一作用域内可见,该作用域可以是包作用域、类型作用域或this 作用域(这意味着如果成员使用了该可见性,this 代表了相同实例,如果类型使用该可见性,则this 表示该类型所在的包)。
作用域内私有 private[scope] 除了对具有继承关系的类的可见性不同之外,与作用域内受保护可见性相同

样式类

使用case修饰的类称为样式类,样式类具有如下特性:

1.隐式地声明字段为val

2.自动混入特质ProductN

3.自动地生成equals, canEqual, hashCode, toString, copy等方法

4.伴生对象中自动生成apply, unapply方法。

示例1:

case class Demo(name: String, age: Int)

特质

scala中的特质就相当于java中接口。但是我们可以在特质中实现方法。

定义特质

trait Car {
  val name: String = "car"
  def run
}

实现特质

class Bus extends Car {

  override val name = "bus"

  override def run: Unit = {
    println("bus running...")
  }

}

测试

val bus = new Bus()
println(bus.name)
bus.run

单继承

和java类似,scala也不允许多继承, 但允许通过with来实现多个接口

trait  Wheel {
  val wheels: Int = 2

  def say
}

class Sedan extends Car with Wheel {

  override val name = "小轿车"

  override def run: Unit = {
    println(s"$name is running...")
  }

  override val wheels = 4

  override def say: Unit = {
    println(s"$name has $wheels wheels")
  }
}

对象实现接口

类在


trait Car {

  val name: String = "car"
  def run

}

class Audi {}

测试

val audi = new Audi with Car {
  override val name = "奥迪"
  override def run: Unit = {
    println(s"$name is running...")
  }
}

audi.run

隐式转换

Scala在面对编译出现类型错误时,提供了一个由编译器自我修复的机制,编译器试图去寻找一个隐式(implicit)的转换方法,转换出正确的类型,完成编译。这就是implicit 的意义。

隐式转换到某个期望类型

用在方法上

class ImplicitToMethod

object ImplicitToMethod {

  //排除implicit的警告
  import scala.language.implicitConversions

  implicit def stringToInt(s: String): Int = Integer.parseInt(s)

  implicit def typeConversion(input: Int): String = input.toString

  implicit def typeConversion(input: Boolean): String = if (input) "true" else "false"

  def plus(x: Int, y: Int): Int = x + y

  def display(input: String): Unit = println(input)

  def apply: ImplicitToMethod = new ImplicitToMethod()
}

测试

object ImplicitTest {
  def main(args: Array[String]): Unit = {
    //必须import隐式转换的方法,否则出错
    import ImplicitToMethod.typeConversion
    ImplicitToMethod.display("1212")
    //编译时调用了隐式转换
    ImplicitToMethod.display(12)
    ImplicitToMethod.display(true)

    import ImplicitToMethod.stringToInt
    //编译时调用了隐式转换
    val result = ImplicitToMethod.plus("3", "2")
    println(result)
  }
}

隐式参数和隐式值形式

隐式参数

def func(implicit x: Int)
def func2(x: Int)(implicit y: Int)
def func3(implicit x: Int, y: Int)

这三种形式是有区别的,在参数中implicit只能出现一次,而在此之后,所有的参数都会变为implicit

隐式值

implicit object Test
implicit val x = 5
implicit var y

作用

这种用法的作用主要是两种用法搭配起来来达到一个效果,隐式参数表明这个参数是可以缺少的,也就是说在调用的时候这个参数可以不用出现,那么这个值由什么填充呢? 那就是用隐式的值。

object ImplicitToValue {

  def funImplicit1(implicit age: Int): Unit = {
    println("funImplicit1: age: " + age)
  }

  def funImplicit2(implicit age: Int, name: String): Unit = {
    println("funImplicit2: age: " + age + ", name:" + name)
  }

  def funImplicit3(age: Int)(implicit name: String): Unit = {
    println("funImplicit3: age: " + age + ", name:" + name)
  }
}

测试

object ImplicitTest {
  def main(args: Array[String]): Unit = {
    implicit val impAge = 30
    implicit val implName = "Jack"

    funImplicit1
    funImplicit2
    funImplicit3(31)

  }
}

隐式类

形式

implicit class MyClass(x: Int)

作用

这里的作用主要是其主构造函数可以作为隐式转换的参数,相当于其主构造函数可以用来当做一个implicit的function


class ImplicitToClass

object ImplicitToClass {

  implicit class MyName(x: Int) {
    val y = x
    println("Test implicit class")
  }

  def say(x: MyName): Unit = {
    println(x.y)
  }
}

测试


object ImplicitTest {
  def main(args: Array[String]): Unit = {
   say(5)
  }
}

这里的MyName是一个隐式类,其主构造函数可以用作隐式转换,所以say需要一个MyName类型的参数,但是调用的时候给的是一个Int,这里就会调用MyName的主构造函数转换为一个MyName的对象,然后再println其y的值