本文转载自微信公众号「大数据摆布手」kaiyun官方网站,作家摆布 。转载本文请关系大数据摆布手公众号。
绪论Scala行为一门面向对象的函数式编程说话,把面向对象编程与函数式编程相接起来,使得代码更粗略高效易于和会。这即是Scala赢得防御的初志。
Scala行为一门JVM的说话,大数据生态的大部分组件齐是Java说话树立的,而Scala不错与Java无缝混编,因此不错很好地和会到大数据生态圈。
主要内容一些基础东西不再排列,比如树立环境,轮回,特殊,泛型等等,本篇只先容独到,特殊的精华所在,留意成见和会与用法。
1.变量和数据类型
2.函数式编程
(a)高阶函数
(b)匿名函数
(c)闭包
(d)函数柯里化
3.面向对象
(a)类与对象
(b)伴生对象
(c)性格
4.风物匹配
5.隐式调理
变量和数据类型变量(var声明变量,val声明常量)
var 修饰的变量可更变
val 修饰的变量不可更变
但确实如斯吗?
关于以下的界说class kaiyun官方网站A(a: Int) { var value = a } class B(b: Int) { val value = new A(b) }效用测试
val x = new B(1) x = new B(1) // 弊端,因为 x 为 val 修饰的,援用不可更变 x.value = new A(1) // 弊端,因为 x.value 为 val 修饰的,援用不可更变 x.value.value = 1 // 正确,x.value.value 为var 修饰的,不错再行赋值
事实上,var 修饰的对象援用不错更变,val 修饰的则不可更变,但对象的情景却是不错更变的。
可变与不可变的和会咱们知说念scala中的List是不可变的,Map是可变和不可变的。不雅察底下的例子
var可变和List不可变的组合
var list = List("左","右") list += "手"和会即是
var list指向的对象是 List("左","右")
后头修改list的指向,因为是可变的var修饰,list又不错指向新的 List("左","右","手")
若是是以下(会报错的)
val list = List("左","右") list += "手"val var与Map可变和不可变
var map = Map( "左" -> 1, "右" ->1, ) map+=("手"->1)
val map=scala.collection.mutable.Map( "左" -> 1, "右" ->1, ) map+=("手"->1)和会
不可变的Map在添加元素的时刻,原本的Map不变,生成一个新的Map来保存原本的map+添加的元素。
可变的Map在添加元素的时刻,并不必重生成一个Map,而是径直将元素添加到原本的Map中。
val不可变的只是指针,跟对象map没关系系。
数据类型 数据类型 描摹 Byte 8位有瑰丽补码整数。数值区间为 -128 到 127 Short 16位有瑰丽补码整数。数值区间为 -32768 到 32767 Int 32位有瑰丽补码整数。数值区间为 -2147483648 到 2147483647 Long 64位有瑰丽补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 Float 32 位, IEEE 754 规范的单精度浮点数 Double 64 位 IEEE 754 规范的双精度浮点数 Char 16位无瑰丽Unicode字符, 区间值为 U+0000 到 U+FFFF String 字符序列 Boolean true或false Unit 默示无值,和其他说话中void等同。用作不复返任何鸿沟的设施的鸿沟类型。Unit唯惟一个实例值,写成()。 Null null 或空援用 Nothing Nothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。 Any Any是整个其他类的超类 AnyRef AnyRef类是Scala里整个援用类(reference class)的基类 函数式编程高阶函数
高阶函数是指使用其他函数行为参数、或者复返一个函数行为鸿沟的函数。在Scala中函数是"一等公民"。
浅薄例子
val list=List(1,2,3,4) val function= (x:Int) => x*2 val value=list.map(function)
设施为函数
def main(args: Array[String]): Unit = { val list=List(1,2,3,4) val value=list.map(function) } def function (x:Int)=x*2
复返函数的函数
def calculate(symbol:String): (String,String)=>String ={ symbol match { case "拼接神气1" => (a:String,b:String)=> s"拼接神气1:$a , $b" case "拼接神气2" => (a:String,b:String)=> s"拼接神气2: $b , $a" } }
val function: (String, String) => String = calculate("拼接神气2") println(function("大数据", "摆布手"))
匿名函数
Scala 中界说匿名函数的语法很浅薄,箭头左边是参数列表,右边是函数体。
使用匿名函数后,咱们的代码变得更粗略了。
var inc = (x:Int) => x+1 var x = inc(7)-1
也可无参数
var user = () => println("大数据摆布手")闭包
闭包是一个函数,复返值依赖于声明在函数外部的一个或多个变量。
闭包每每来讲不错浅薄的觉得是不错走访一个函数里面局部变量的另外一个函数。
浅薄和会即是:函数里面的变量不在其作用域时,仍然不错从外部进行走访。
val function= (x:Int) => x*2
闭包的履行即是代码与用到的非局部变量的夹杂
闭包 = 代码 + 用到的非局部变量
val fact=2 val function= (x:Int) => x*fact
函数柯里化
柯里化指的是将原本接纳两个参数的函数形成新的接纳一个参数的函数的进程。新的函数复返一个以原有第二个参数为参数的函数。
先界说一个浅薄的
def add(x:Int,y:Int)=x+y 使用 add(1,2)
函数变形(这种神气就叫柯里化)
def add(x:Int,y:Int)=x+y 使用 add(1,2)
竣事进程
add(1)(2) 履行上是循序调用两个通俗函数(非柯里化函数)
第一次调用使用一个参数 x,复返一个函数类型的值。
第二次使用参数y调用这个函数类型的值。
经受一个x为参数,复返一个匿名函数 经受一个Int型参数y,函数体为x+y。 def add(x:Int)=(y:Int)=>x+y (1) val result = add(1) // result= (y:Int)=>1+y (2) val sum = result(2) (3) sum=3面向对象
类和对象
类是对象的空洞,而对象是类的具体实例。类是空洞的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个界说包括在特定类型的对象中的设施和变量的软件模板。
类不错带有类参数
类参数不错径直在类的主体中使用。类参数通常不错使用var作前缀,还不错使用private、protected、override修饰。scala编译器会网罗类参数并创造出带通常的参数的类的主构造器。,并将类里面任何既不是字段也不是设施界说的代码编译至主构造器中。
class Test(val a: Int, val b: Int) { // }
样例类
case class一般被翻译成样例类,它是一种特殊的类,简略被优化以用于风物匹配。
当一个类被申明为case class的时刻。具有以下功能:
构造器中的参数若是不被声明为var的话,它默许的是val类型的。 自动创建伴生对象,同期在里面给咱们竣事子apply设施,使咱们在使用的时刻不错不径直使用new创建对象。 伴生对象中通常会帮咱们竣事unapply设施,从而不错将case class哄骗于风物匹配。 竣事我方的toString、hashCode、copy、equals设施case class person( name:String, age:Int )
对象与伴生对象
Scala单例对象是十分病笃的,莫得像在Java一样,有静态类、静态成员、静态设施,然而Scala提供了object对象,这个object对象雷同于Java的静态类,它的成员、它的设施齐默许是静态的。
界说单例对象并不代表界说了类,因此你不不错使用它来new对象。当单例对象与某个类分享并吞个称呼时,它就被称为这个类的伴生对象。
类和它的伴生对象必须界说在并吞个源文献里。类被称为这个单例对象的伴生类。
类和它的伴生对象不错相互走访其额外成员。
object Test { private var name="大数据" def main(args: Array[String]): Unit = { val test = new Test() println(test.update_name()) } } class Test{ def update_name(): String ={ Test.name="摆布手" Test.name } }
性格(trait)
scala trait相配于java 的接口,履行上它比接口还功能精深。与接口不同的是,它还不错界说属性和设施的竣事。
一般情况下scala的类只简略剿袭单一父类,然而若是是trait 的话就不错剿袭多个,从鸿沟来看即是竣事了多重剿袭(要津字with)。其实scala trait更像java的空洞类。
object Test extends UserImp with AddressImp { override def getUserName(): String = ??? override def getAddress(): String = ??? } trait UserImp{ def getUserName():String } trait AddressImp{ def getAddress():String }风物匹配
以java 的 switch 为例,java 的 switch 只是会作念一些基本类型的匹配,然后实行一些动作,何况是莫得复返值的。
而 scala 的 pattern matching match 则要精深得多,除了不错匹配数值,同期它还能匹配类型。
def calculate(symbol:String): (String,String)=>String ={ symbol match { case "拼接神气1" => (a:String,b:String)=> s"拼接神气1:$a , $b" case "拼接神气2" => (a:String,b:String)=> s"拼接神气2: $b , $a" } }
让我吃惊的是(就短短几行)
快排 def quickSort(list: List[Int]): List[Int] = list match { case Nil => Nil case List() => List() case head :: tail => val (left, right) = tail.partition(_ < head) quickSort(left) ::: head :: quickSort(right) } 归并 def merge(left: List[Int], right: List[Int]): List[Int] = (left, right) match { case (Nil, _) => right case (_, Nil) => left case (x :: xTail, y :: yTail) => if (x <= y) x :: merge(xTail, right) else y :: merge(left, yTail) }隐式调理
Scala提供的隐式调理和隐式参数功能,是曲常有特色的功能。是Java等编程说话所莫得的功能。它不错允许你手动指定,将某种类型的对象调理成其他类型的对象。通过这些功能,不错竣事极度精深,而且特殊的功能。
轨则
(1)在使用隐式调理之前,需要用import把隐式调理援用到刻下的作用域里或者就在作用域里界说隐式调理。
(2)隐式调理只可在无其他可用调理的前提下技能操作。若是在并吞作用域里,对并吞源类型界说一个以上的隐式调理函数,若是多种隐式调理函数齐不错匹配,那么编译器将报错,是以在使用时请移除不必要的隐式界说。
数据类型的隐式调理
String类型是不可自动调理为Int类型的,是以当给一个Int类型的变量或常量赋予String类型的值时编译器将报错。然而.....
implicit def strToInt(str: String) = str.toInt def main(args: Array[String]): Unit = { val a:Int="100" print(a) }
参数的隐式调理
所谓的隐式参数,指的是在函数或者设施中,界说一个用implicit修饰的参数,此时Scala会尝试找到一个指定类型的,用implicit修饰的对象,即隐式值,并注入参数。
object Test { private var name="大数据" implicit val test = new Test def getName(implicit test:Test): Unit ={ println(test.update_name()) } def main(args: Array[String]): Unit = { getName } } class Test{ def update_name(): String ={ Test.name="摆布手" Test.name } }