scala变量
声明变量
普通变量
var a: String = "Foo"
var b: Int = 20
数组
var c: Array[String] = Array("a", "b")
var d = Array(1,2)
var e = new Array[Int](2)
e(0) = 100
元组
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的值