-
Scala精华之处就在这里,拿去,口试也不怕
发布日期:2022-05-10 09:18 点击次数:198本文转载自微信公众号「大数据傍边手」,作家傍边 。转载本文请关系大数据傍边手公众号。
绪言Scala手脚一门面向对象的函数式编程话语,把面向对象编程与函数式编程勾搭起来,使得代码更纯粹高效易于相识。这即是Scala得回爱好的初志。
Scala手脚一门JVM的话语,大数据生态的大部分组件都是Java话语建筑的,而Scala不错与Java无缝混编,因此不错很好地交融到大数据生态圈。
主要内容一些基础东西不再陈设,比如建筑环境,轮回,极端,泛型等等,本篇只先容独到,特地的精华地点,预防想法相识与用法。
1.变量和数据类型
2.函数式编程
(a)高阶函数
(b)匿名函数
(c)闭包
(d)函数柯里化
3.面向对象
(a)类与对象
(b)伴生对象
(c)脾气
4.模式匹配
5.隐式颐养
变量和数据类型变量(var声明变量,val声明常量)
var 修饰的变量可改造
val 修饰的变量不可改造
但确切如斯吗?
关于以下的界说class 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 } }