https://docs.scala-lang.org/zh-cn/tour/higher-order-functions.html
case class
case class
样例类,必须要有参数列表;case object
样例对象,必须不能加参数列表。案例类非常适合用于不可变的数据,Spark
中常用 case class
来存储信息。case class
相比于 class
有什么不同(以下这些都是编译器实现):
case class
重写了toString
、equals
、hashCode
case class
默认就实现了序列化case class
不用new
,有一个默认的apply
方法来负责对象的创建case class
的copy
内部实现是new
对象
object CaseClassApp {
def main(args: Array[String]): Unit = {
println(Dog("john").name)
}
case class Dog(name:String)
}
case class
按值比较
object CaseClassApp {
def main(args: Array[String]): Unit = {
val dog1 = Dog("john")
val dog2 = Dog("john")
println(dog1 == dog2) // true
}
case class Dog(name:String)
}
柯里化
一个接受多个参数的函数分解成一系列的函数,每个函数只接受一个参数,这个过程叫做柯里化。
currying
最大的意义在于把多个参数的函数等价转化成多个单参数函数的级联,这样所有的函数就都统一了,方便做 lambda
演算。
object Currying {
def main(args: Array[String]): Unit = {
// 参数必须分开写
def sum(a:Int)(b:Int) = a + b
// 柯里化产生新的函数 sum9
// 此函数功能:形参 + 9
val sum9 = sum(9)_ //还有参数必须加 "_"
println(sum9(5)) // 14
println(sum9(10)) // 19
}
}
下面来看看 currying
的演化,省得下次看到不认识
// 以下四个函数的作用都是两者之和
scala> def sum(x:Int,y:Int) = x + y
sum: (x: Int, y: Int)Int
scala> def sum = (x:Int,y:Int) => x + y
sum: (Int, Int) => Int
scala> def sum(x:Int)(y:Int) = x + y
sum: (x: Int)(y: Int)Int
scala> def sum = (x:Int) => (y:Int) => x + y
sum: Int => (Int => Int)
偏函数
PartialFunction
:包在花括号内没有match
的case
语句;重点理解
偏函数接收一个类型为A的参数,返回类型为B的值
object PartialFunctionApp {
def main(args: Array[String]): Unit = {
val names = Array("li","wang","zhang")
val name = names(new Random().nextInt(names.length))
def say:PartialFunction[String,String] = {
case "li" => "name is li"
case "wang" => "name is wang"
case "zhang" => "name is zhang"
case _ => "no"
}
println(say(name))
}
}
隐式转换
增强现有代码:悄无声息
隐式参数
可以提供相同的默认值
def say(implicit word:String) = println(s"hello $word")
implicit val word = "danner"
// 输出 hello danner
say
当方法/函数的参数用 implicit
修饰时,会寻找上下文中用implicit
修饰的相同类型的变量。在本例中,say
的隐式参数是String
且没有带参数,那么此时会寻找类型为 String
且被implicit
修饰的变量直接代入 say
函数。
隐式类型转换
为已存在的类添加新方法
object ImplicitApp {
def main(args: Array[String]): Unit = {
// 为现有 Man 类添加 fly 函数
implicit def man2superman(man: Man) = new Superman(man.name)
val man = new Man("danner")
man.fly()
implicit def str2Int(string: String):Int = new StringOps(string).toInt
// 无声息地将字符串转化为 Int
println(math.max("2",3))
}
}
class Man(val name:String)
class Superman(val name:String) {
def fly(): Unit = {
println(s"$name fly ...")
}
}
隐式类
实现与隐式类型转换类似功能
implicit class EnMan(man:Man){
def fly(): Unit ={
println(s"EnMan ${man.name} can fly ...")
}
}
val john = new Man("john")
john.fly // EnMan john can fly ...
为 Man
类增加 fly
方法
弊端
代码执行流程不清晰,你可能都看不明白
泛型
对类型的约束
object GenericApp {
def main(args: Array[String]): Unit = {
// 只能是子类
testUpperBounds(new Child)
testUpperBounds(new User)
// scala 2.11.8 是可以传 Child
testLowerBounds(new Person)
testLowerBounds(new Child)
testLowerBounds(new User)
}
// 上界:约束 T 是 User 或子类
def testUpperBounds[T <: User](t:T): Unit ={
println(t)
}
// 下界:约束 T 是 User 或父类?不同版本表现不同,
def testLowerBounds[T >: User](t:T): Unit ={
println(t)
}
}
class Person
class User extends Person
class Child extends User
逆变
子类 ==> 父类,减少功能
// 传递子类
val person = new Test[Person]
println(person)
class Person
class User extends Person
class Child extends User
// 逆变
class Test[-User]
协变
父类 ==> 子类,增强功能
val child = new Test[Child]
println(child)
class Person
class User extends Person
class Child extends User
// 协变
class Test[+User]
ScalikeJDBC
官网 ScalikeJDBC 是 Scala 开发人员基于 SQL 的简洁数据库访问库
application.conf
数据库连接配置:src/main/resources/application.conf
# MySQL example
db.default.driver="com.mysql.jdbc.Driver"
db.default.url="jdbc:mysql://192.168.22.147:3306/rz_db"
db.default.user="root"
db.default.password="123456"
# Connection Pool settings
db.default.poolInitialSize=10
db.default.poolMaxSize=20
db.default.connectionTimeoutMillis=1000
code
查询 platform_stat
object ScalikeJDBCApp {
def main(args: Array[String]): Unit = {
// 初始化 JDBC 配置,加载 application.conf
DBs.setupAll()
// 查询示例
query()
}
def query()={
val offsets = DB.readOnly({
implicit session => {
SQL("select * from platform_stat").map(rs => {
platform(
rs.string("platform"),
rs.int("cnt"),
rs.string("d")
)
}).list().apply()
}
})
// 输出
offsets.foreach(println)
}
}
case class platform(platform:String,cnt:Int,time:String)
参考资料
深入理解scala的柯里化( currying or curry )以及其用处
偏函数 vs 部分应用函数 vs 柯里化