相比java的不同
类型层次
scala 相比 java,特有的特性:
- 高阶函数,函数柯里化
- 隐式转换
- case class,消除了set、get
- lazy 延迟计算
- if else 中可以直接返回结果,没有return了
- 内置的可变,不可变集合类
- 自动类型推导
- 操作符重载
- 模式匹配
- 内部函数
- 对象值的 apply,unapply
- None,Some,Option
例子
apply 和 unapply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import scala.util.Random
object CustomerID {
def apply(name: String) = s"$name--${Random.nextLong()}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
}
}
val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
customer1ID match {
case CustomerID(name) => println(name) // prints Sukyoung
case _ => println("Could not extract a CustomerID")
}
|
case class
1
|
case class Point(x: Int, y: Int)
|
入口点
1
2
3
4
|
object Main {
def main(args: Array[String]): Unit =
println("Hello, Scala developer!")
}
|
constructors
1
2
3
4
5
|
class Point(var x: Int = 0, var y: Int = 0)
val origin = new Point // x and y are both set to 0
val point1 = new Point(1) // x is set to 1 and y is set to 0
println(point1) // prints (1, 0)
|
trait
1
2
3
4
|
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
|
tuple
1
|
val ingredient = ("Sugar", 25)
|
高阶函数
1
2
3
|
val salaries = Seq(20_000, 70_000, 40_000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary)
|
函数 柯里化
1
2
3
4
5
6
7
8
9
10
11
12
|
// A normal function that adds two numbers
def add(x: Int, y: Int): Int = x + y
// A curried version of the same function
def addCurried(x: Int)(y: Int): Int = x + y
// Usage
val add5 = addCurried(5) _ // Partially apply the function
println(add5(10)) // Outputs: 15
// Alternatively
println(addCurried(3)(7)) // Outputs: 10
|
foldLeft
1
2
3
|
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val res = numbers.foldLeft(0)((m, n) => m + n)
println(res) // 55
|
模式匹配
1
2
3
4
5
6
7
8
9
10
|
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
case Email(sender, _, _) if importantPeopleInfo.contains(sender) =>
"You got an email from special someone!"
case SMS(number, _) if importantPeopleInfo.contains(number) =>
"You got an SMS from special someone!"
case other =>
showNotification(other) // nothing special, delegate to our original showNotification function
}
}
|
for 循序,有点像 python
1
2
3
4
5
6
7
8
9
10
11
12
13
|
case class User(name: String, age: Int)
val userBase = List(
User("Travis", 28),
User("Kelly", 33),
User("Jennifer", 44),
User("Dennis", 23))
val twentySomethings =
for (user <- userBase if user.age >=20 && user.age < 30)
yield user.name // i.e. add this to a list
twentySomethings.foreach(println) // prints Travis Dennis
|
隐式类型转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
object FileExtensions {
implicit class RichFile(file: File) {
// Method to read the entire file content as a string
def readAsString(): String = {
val sb = new StringBuilder
var reader: BufferedReader = null
try {
reader = new BufferedReader(new FileReader(file))
var line: String = reader.readLine()
while (line != null) {
sb.append(line)
sb.append(System.lineSeparator()) // For new line
line = reader.readLine()
}
} catch {
case e: IOException => e.printStackTrace()
} finally {
if (reader != null) reader.close()
}
sb.toString()
}
}
}
val file = new File("example.txt")
file.readAsString
|
隐式转换的几个例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 1、类型转换
implicit def doubleToInt(d: Double): Int = d.toInt
val x: Int = 42.5 // Implicitly converts Double to Int
println(x) // Outputs: 42
// 2、隐式类
implicit class RichInt(val x: Int) {
def square: Int = x * x
}
println(5.square) // Outputs: 25
// 3、隐式参数
implicit val defaultMultiplier: Int = 2
def multiply(x: Int)(implicit multiplier: Int): Int = x * multiplier
println(multiply(5)) // Outputs: 10, using the implicit multiplier (2)
|
操作符重载
1
2
3
4
5
6
7
8
9
10
|
case class Vec(x: Double, y: Double) {
def +(that: Vec) = Vec(this.x + that.x, this.y + that.y)
}
val vector1 = Vec(1.0, 1.0)
val vector2 = Vec(2.0, 2.0)
val vector3 = vector1 + vector2
vector3.x // 3.0
vector3.y // 3.0
|
By-name Parameters,传递参数的时候,可以延迟计算
1
|
def calculate(input: => Int) = input * 37
|
package
1
2
3
4
5
6
7
8
|
package users {
package administrators {
class NormalUser
}
package normalusers {
class NormalUser
}
}
|
逆变、协变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
object Demo {
def main(args: Array[String]): Unit = {
//非变案例演示
val A:Temp1[Sub] = new Temp1[Sub]
//val B:Temp1[Super] = A //非变, 编译报错,不能赋值。
//尽管类型A是B的子类型,Pair[A]和Pair[B]没有任何从属关系,参数化类型之间没有关系,不管原类型之间的关系
// 协变案例演示
val C: Temp2[Sub] = new Temp2[Sub]
val D: Temp2[Super] = C
//类型C是D的子类型,Pair[C]可以认为是Pair[D]的子类型,参数化类型的方向和类型的方向是一致的。
// 逆变案例演示
val E: Temp3[Super] = new Temp3[Super]
val F: Temp3[Sub] = E
//类型F是E的子类型,Pair[E]反过来可以认为是Pair[F]的子类型。参数化类型的方向和类型的方向是相反的
}
}
|
协变解释
- Covariance (+A)
- 类型B是A的子类型,Pair[B]可以认为是Pair[A]的子类型
- 参数化类型的方向和类型的方向是一致的
逆变解释
- Contravariance (-A)
- 类型B是A的子类型,Pair[A]反过来可以认为是Pair[B]的子类型
- 参数化类型的方向和类型的方向是相反的
上界、下界
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 使用<: 类型名表示给类型添加一个上界,表示泛型参数必须要从该类(或本身)继承
class Person
class Student extends Person
def demo[T <: Person](a:Array[T]) = println(a)
def demo2[T >: Student](a:Array[T]) = println(a)
// A method that combines both upper and lower bounds
// T must be a supertype of Student (lower bound) and a subtype of Person (upper bound)
def demo3[T >: Student <: Person](a: Array[T]): Unit = {
a.foreach(_.speak()) // Call the speak method on each element
}
def main(args: Array[String]): Unit = {
demo(Array(new Person))
demo(Array(new Student))
// 编译出错,必须是Person的子类
// demo(Array("hadoop"))
}
|
解释
- 上界:T <: Person,表示 T 必须是 Person 的子类型
- 下界:T >: Student,表示 T 必须是 Student 的父类型
- T >: Student <: Person:表示 T 是Student的父类型,又是 Person的子类型
参考