Scala编程指南

1.scala简介

2004年,martin ordersky发明,javac的编译器,后来spark,kafka应用广泛,twitter应用推广。它具备面向对象和函数式编程的特点。
官网:www.scala-lang.org,最近版本2.12.5,我们用的是2.10.4

2.环境安装

1) windowsa) 安装jdk-7u55-windows-x64.exeb) 安装scala-2.10.4.msi安装完以上两步,不用做任何修改。测试:在控制台下c:/>scalac) 安装eclipse-java-juno-SR2-win32-x86_64.zip 解压缩即可d) 安装eclipse的scala插件update-site.zip解压会有两个目录,features和plugins,分别把内容放到eclispe对应的目录下。 e) 重启eclipse提示"Upgrade of scala...",点yes提示框"setup Diagnostic",把Enable JDT weaving...选上根据提示重启
2) linux

3.第一个程序

1) 交互式编程C:\Users\Administrator>scalaWelcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_5Type in expressions to have them evaluated.Type :help for more information.scala> 1+1res0: Int = 22) 脚本形式:通过创建文件来在eclipse/idea中执行代码object Test {def main(args: Array[String] ) {println("Hello world")}}注1:上面这个是单例对象,这个里面只能存放静态的东西注2:自动导入2个包java.lang._scala._注3:语句最后一行的分号不推荐写

4.基础语法

1) 变量和常量

    val(常量)和var(变量) 尽可能的用val(1) 变量格式:var 变量名 [:数据类型] = 值例:var b :Int = 1var c = 2   //类型自动推断(2) 常量格式:val 常量名 [:数据类型] = 值例:val b :Int = 1val b = 1b = 2   //报错,常量不能修改(3) 常量可以用lazy修饰(了解)lazy val b :Int = 1 //b用到的时候再赋值

2) 数据类型

    (1)数据类型序号  数据类型    说明1   Byte    8位有符号值,范围从-128至1272   Short   16位有符号值,范围从-32768至327673   Int     32位有符号值,范围从-2147483648至21474836474   Long    64位有符号值,范围从-9223372036854775808至92233720368547758075   Float   32位IEEE 754单精度浮点值6   Double  64位IEEE 754双精度浮点值7   Char    16位无符号Unicode字符。范围从U+0000到U+FFFF8   String  一个Char类型序列9   Boolean 文字值true或文字值false10  Unit    对应于无值,等价于void类型,只有一个对象叫()11  Null    只有一个对象叫null12  Nothing 在Scala中处于最底层,比如创建数组时不指定类型,就是Noting。抽象概念13  Any     任何类型的超类型; 任何对象的类型为Any14  AnyRef  任何引用类型的超类型(2)层次结构Scala.Any-AnyVal(值)-Int,Double等,Unit。-AnyRef(引用)-List,Set,Map,Seq,Iterable-java.lang.String-Null(3)重点类型:元组格式:(元素1, 元素2, ....)访问:变量._N 其中N是元组元素的索引,从1开始例:var t = ("a", false, 1)       //t的类型是scala.Tuple3var value = t._1    //"a"var m,n,(x,y,z) =  ("a", false, 1) m   :("a", false, 1) n   :("a", false, 1)x   : 'a'y   : false:z   : 1(4)重点类型:字符串i) 用的是java.lang.String,但是有时候根据需要,会隐式转换到其它类型,比如调用reverse/sorted/sortWith/drop/slice等方法,这些方法定义在IndexedSeqOptimized中ii)多行字符串表示,开始和结束用(4)重点类型:字符串i)用的是java.lang.String,但是有时候根据需要,会隐式转换到其它类型,比如调用reverse/sorted/sortWith/drop/slice等方法,这些方法定义在IndexedSeqOptimized中ii)多行字符串表示,开始和结束用(5)了解:符号类型符号字面量: '标识符,是scala.Symbol的实例,像模式匹配,类型判断会比较常用。var flag = 'startif (flag == 'start) println(1) else println(2)

3) 运算符:scala没有运算符,它运算符全部封装成了方法。

    算术:+ - * / %比较: == != > < >= <= 逻辑:&& || !赋值:= += -= *= /* %=位:& | ~ ^ >> << >>>  #*/注:上面都是方法。例 1+2相当于1.+(2),其中+是方法,2是参数

4) 控制语句

    (1) if,if...else...,if...else if...else...(2) scala中的if可以作为表达式用var x = if("hello"=="hell") 1 else 0(3) switch被模式匹配替换

5) 循环语句

    (1)while,do..while和for都有,while和do..while很像,但是for差别很大。(2)for循环格式不同for(变量 <- 集合 if 条件判断1;if 条件判断2...) {所有条件判断都满足才执行}(3)没有break和continue,用两种方法可以代替i) 用for循环的条件判断ii)方法2:非写break,要做以下两步//1) 引入一个包scala.util.control.Breaks._//2) 代码块用breakable修饰breakbreakable {for(i<-0 to 10) {println(i)if (i == 5) {break;}}}//0 1 2 3 4 5continuefor(i<-0 to 10) {breakable {if (i == 3 || i==6) {break;}println(i)}}//0 1 2 4 5 7 8 9 10(5) 集合框架(Array,List,Set,Map)在scala中,数组Array归到集合的范畴包scala.collection,下面有两个分支immutable(不可改变的,默认)和mutable(可变的)(1) 层次结构Traversable-Iterable(immutable不可改变的长度,默认)-Set 无序的集合,没有重复元素HashSet,TreeSt  其中HashSet内部定义了别名Set-Map  键值对,映射HashMap,TreeMap  其中HashMap内部定义了别名Map-Seq  序列。有先后顺序的元素集合-IndexedSeqArray:有索引的元素序列,因此可以通过下标访问Vector,String,Range-LinearSeqList:线性的元素序列。访问第1个元素,head方法,最后1个tail方法Queue,Stack(mutable可变的长度)-SetHashSet  其中HashSet内部定义了别名Set-MapHashMap  其中HashMap内部定义了别名Map-Seq-IndexedSeqArraySeq,StringBuilder-BufferArrayBuffer,ListBuffer-LinearSeqLinkedList,QueueStack重点记忆几个不可变 可变Array   ArrayBufferList    ListBufferMap     MapSet     Set(2) 数组(非常重要):数据类型相同的元素,按照一定顺序排序的集合。不可变数组 scala.Array可变长数组 scala.collection.mutable.ArrayBufferArray和ArrayBuffer1.Array创建var 变量名 = new Array[类型](长度) //var arr = new Array[Int](10)var 变量名 = Array(元素1,元素2,...) //var arr = Array(1,3,5,7),实际上是调用Array的方法apply取值:变量名(下标)2.ArrayBuffer创建var 变量名 = new ArrayBuffer[类型]() //var arr = new ArrayBuffer[Int]()var 变量名 = ArrayBuffer(元素1,元素2,...) //var arr = ArrayBuffer(1,3,5,7)3.共同方法sum 求和max 最大值min 最小值mkString(分隔符)   例:Array(1,3,5,7).mkString("|")  //结果是1|3|5|7|9sorted 排序(从小到大)sortBysortWith 自定义排序reverse 翻转toArray ArrayBuffer转成ArraytoBuffer Array转成ArrayBuffertoMap:如果Array内部元素是对偶元组,可以转成maptoList:转成list4.ArrayBuffer的独有方法+= 追加元素++= 追加集合trimEnd(n):删除末尾n个元素insert(index,value1,value2,..valueN):第index的位置,插入value1,value2,...valueN)remove(index,n):第index个位置删除n个元素clear():清空5.遍历i) 通过下标for (i <- 0 to 数组.length-1) {println(i)) //i表示数组的下标}ii)直接取值for (e <- 数组) {println(e)}6.使用yield创建新数组var arr = for (i <- 数组) yield i * 27.多维数组var arr = Array(Array(元素1...),Array(元素,...)..)遍历for (i <- arr) {for (j <- i) {println(j)}}               (3) List(不可变)/ListBuffer(可变):List 和java.util.List不同,一旦创建不可以改变。一般做数据分析用List1.List定义//创建var list1 = List("aa","bb","ccc")   //调用apply方法var list2 = List.apply("aa","bb","ccc"))//右操作符:当方法名以:结尾时,为右操作符,先做右边//::右操作符,拼接元素,var list3 = "aa"::"bb"::"cc"::Nil   //Nil是空集合,先做"cc"::Nil,其中::是Nil的方法var list4 = list1:::"dd"::Nil   //:::拼接集合2.常用方法//查head() 第一个元素take(n) 取前n个元素tail() 除了第1个的全部元素init() 除了最后一个的全部元素//增:+和+:  前者是尾部追加元素,后者是在头部追加元素,和::很像+=或append 追加元素(ListBuffer)++= 追加数组/列表(ListBuffer):: 追加元素(List)::: 追加数组/列表(List)//删drop(n) 丢弃前n个元素//改         updated(index,value):用value地替换第index的位置的元素//其他isEmpty是否为空reverse 翻转splitAt(m):把列表前m个做成一组,后面是一组flatten:以参数的列表作为参数,把所有的元素连接到一起//toArray 转成ArraytoArray 转成Arrayzip:两个List内部的元素合并,返回结果是List,元素是对偶元组grouped(n):每n个元素分成1组,返回是迭代器Iterator,可以再用toList转成list类型3.ListBufferimport scala.collection.mutable.ListBuffervar list5 = ListBuffer("111","222","333")(4) Set:不存在重复元素的集合如果用可变的,需要引入import scala.collection.mutable.Set//定义var s = Set(3.0, 1.0)//追加元素s += 2.0    //s = s + 2.0s += 2.0    //元素重复,加不进去(5) Map//定义var m1 = Map(("zhang3",20),("li4",23),("wang5",21)) //使用元组var m2 = Map(("zhang3"->20),("li4"->23),("wang5"->21))var m3 = Map[String,Int]()  //定义空map,得用可变的才有意义。//添加和更新 var m = scala.collection.mutable.Map(("zhang3", 20), ("li4", 23), ("wang5", 21))m += (("zhao6", 22)) //m = m.updated("zheng7",19) //和上面方法一样m.put("wu", 22)     m ++= Map(("a" -> 1), ("b" -> 2))//删除m -= (("zhao6", 22))m.clear() 清空//查询m(key):通过key获取valuem.get(key) :通过key获取value,返回类型Optionm.getOrElse(key,获取不到设置的值)//其它size:元素个数contains(key):是否包含key,返回布尔类型keys 返回迭代器keySet 返回所有的key组成的Set集合values 返回迭代器,所有value组成的集合mapValues(函数)foreach(函数)//遍历(6) Array和List都是不可变元素,有什么区别?

5.函数

Scala中函数和方法,在类中定义的函数就是方法。

1) 函数声明

    def 函数名([参数列表]):[返回类型] = {函数体return [表达式]}注1:如果函数没有返回值,可以返回Unit,也可以不写注2:方法的返回类型可以不写,系统自动推导,但是递归必须写。注3:函数体的大括号只有一行,可以不写例:def add(a:Int,b:Int):Int = {var sum : Int = 0sum = a + breturn sum}

2) 函数调用

    格式:方法之间调用:函数名([实参列表])  例:add(3,5)对象之间调用:实例名.函数名([实参列表])  例:s.add(3,5)

3) 值函数

    (1)定义var 变量名:[输入类型=>输出类型] = {(参数列表)=>{函数体}}其中=>是函数映射符在参数列表后不能写返回值类型最后一句不能写returnLambda表达式(匿名函数,函数字面量):形如(参数列表)=>{函数体}就叫Lambda表达式

4) 高阶函数

    1) 定义:本身是函数,参数也是函数或返回值是函数例1:def m(f:(Double)=>Double):Double = {f(100)}def sqrt(x:Double)=Math.sqrt(x)调用m(sqrt) 结果是10.02) 常见高阶函数集合中常见的高阶函数(1)map  def map[B, That](f: A => B): That 把函数应用于集合中的每一个元素,把返回由返回值组成的一个集合。例:Array("spark","hive","haddop").map((x:String)=>x.length)Array("spark","hive","haddop").map(x=>x.length)Array("spark","hive","haddop").map(_.length) // _占位符,代表一个元素Array("spark","hive","haddop").map(x=>println(x))Array("spark","hive","haddop").map(println _)Array("spark","hive","haddop").map(println) //如果只有一个参数,可以不写(2) flatMap把函数应用于集合中的每一个元素,先做map,得到的结果flatten,生成新的集合。例:var list = List("a,b,c","d,e,f")var list2 = list.map(x=>x.split(",").toList) //List(List(a, b, c), List(d, e, f))list2.flatten  //List(a,b,c,d,e,f)上面两步可以写成一步,相当于map+flatternlist.flatMap(x=>x.split(",").toList) //简写:list.flatMap(_.split(",").toList)问:map和flatMap有什么区别?(3)filter参数的函数表示对集合的每个元素过滤,参数函数结果是boolean,最后的返回值还是ListList(1,2,3,4).filter(x=>x>2)    //List(3,4)Array(1,2,3,4,5,6,7,8).filter(x=>x%2==0) //取偶数 2,4,6,8Range(1,100).filter(_%2==0) //1到100的偶数Array(1,2,3,4,5,6,7,8).filter(x=>x%2==0).map(_*10)//20,40,60,80注:filterNot和filter相反(4)reduce/reduceLeft/reduceRight返回1个值。参数函数要求是二元运算符,作用于集合上,每次返回的结果作为新的输入。Array(1,3,5,7).reduce((x,y)=>{println(x + ":" +y);x+y})Array(1,3,5,7).reduce(_+_)  //第1个_代表第1个参数,第2个_代表第2个参数Array(1,3,5,7).reduceLeft((x,y)=>{println(x + ":" +y);x+y})Array(1,3,5,7).reduceRight((x,y)=>{println(x + ":" +y);x+y})注:reduce没有特别的顺序,reduceLeft从左到右计算,reduceRigth从右到左计算(5)fold/foldLeft/foldRight和reduce很像,只是增加了一个初始值,但是做并行时要注意。Array(1,3,5,7).fold(4)(_+_)     //20List(2.0,3.0).fold(4.0)(Math.pow)  //4096.0(6) par把计算转换为并行化,把reduce拆分多个任务Array(1,3,5,7,8).par.fold(4)(_+_)Range(1,10).par.map(println)(7) groupBy 对列表进行分组,返回结果是mapvar data = List(("zhang3","male"),("li4","female"),("wang5","male"))data.groupBy(x=>x._2) //Map(male-> List((zhang3,male), (wang5,male)), female -> List((li4,female)))多介绍一个grouped(n):每n个分成一组例:List(1,3,5,7,9).grouped(2).toList //List(List(1, 3), List(5, 7), List(9))(8)partition把列表分成两部分,第一个为满足条件的,第二部为不满足条件的List(1,3,5,7,9).partition(x=>x>4) //分成两组:(List(5, 7, 9),List(1, 3))(9)diff差集,union并集并保留重复,intersect交集var n1 = List(1,2,3)var n2 = List(2,3,4)var n3 = n1.diff(n2) //也可以写n1 diff n2 ,结果:List(1)var n4 = n2.diff(n1) //List(4)var n5 = n1 union n2    //List(1 2 3 2 3 4)var n6 = n1 intersect n2    //List(2,3)(10)distinct去掉重复元素List(1,2,3,2,3,4).distinct // List(1, 2, 3, 4)(11)mapValues(函数)还是map功能,只是处理的值是value,最终结果是mapMap(("zhang3",20),("li4",23),("wang5",21)).mapValues(_*2)//结果Map(zhang3 -> 40,li4 -> 46,wang5 -> 42)(12)foreach(函数)和map一样,区别是它没有返回值,通常用在遍历(13)sorted 排序和sortBy和sortWithsorted 排序,最简单,从小到大List(2,1,3,5,6,4).sorted    //1 2 3 4 5 6sortBy:按照第几列排List(("a",3),("b",1),("c",2)).sortBy(_._2) //按照第2列排sortWith:自定义排序List(2,1,3,5,6,4).sortWith((x,y)=>x>y) //从大到小3)下划线_的用法(1) 让匿名函数更简洁,可以用下划线_当做一个占位符。(2) java中导入包下的所有类用*,在scala中用_例:Java:  import java.util.*scala: import java.util._(3) 下划线_可以作为部分应用函数4) 函数柯里化柯里化(curring) 把接收多个参数的函数编程接收一个单一参数例1:不是柯里化,但是和柯里化很像def foo(factor : Int) = (x:Double)=>factor * x;调用:var f = foo(10)f(50)也可以直接写:foo(10)(50)例2:柯里化def foo(factor : Int)(x:Double) = factor * x调用:foo(10)(50)注:柯里化函数不是高阶函数,不能这么调用var f = foo(10)5)部分应用函数(Partial Applied Function)部分应用函数, 是指一个函数有N个参数, 而我们为其提供少于N个参数, 那就得到了一个部分应用函数.,柯里化函数和普通函数都有部分应用函数6)偏函数(Partial Function)(1)简介引子:scala> List(1,2,3) map {case i:Int=>i+1}scala> List(1,2,3) map {(i:Int)=>i+1}上面两个结果是一样的。偏函数:上面例子中map后面的被包在花括号内的代码,也就是没有 match的一组case语句,就叫偏函数。偏函数类型是:PartialFunction[A,B],A的参数类型,B是返回结果类型。平常我们都是直接用。例1:val foo : PartialFunction[Int,String] = {   //类型PartialFunction[Int,String]可以省略case y if y % 2 == 0 => y + " 是偶数"}println(foo(10)) //10 is Evenprintln(foo(11)) //抛出错误: scala.MatchError----反编译:相当于foo是一个对象,调用对象的 apply方法private final PartialFunction foo = new PartialFunction{public final Object apply(int i){Object obj;if (i % 2 == 0)obj = y + " 是偶数"elseobj = i;return obj;}}foo.apply(10)   (2)orElse:可以把多个偏函数结合起来,效果类似case语句。val or1 = {case 1 => "One"}val or2 = {case 2 => "Two"}val or_ = {case _ => "Other"}val or = or1 orElse or2 orElse or_ //使用orElse将多个偏结合起来//测试:scala> or(1)    // one        scala> or(20)   //other(3) andThen: 相当于方法的连续调用,比如g(f(x))。  val a = {case cs if cs == 1 => "One"}val b = {case cs if cs eq "One" => "The num is 1"}val c = a andThen b//测试num(1)  //The num is 1(4) 普通函数的偏应用函数定义比如我先定义一个函数:def sum(a:Int,b:Int,c:Int) = a + b + c;那么就可以从这个函数衍生出一个偏应用函数是这样的:def foo = sum(1, _:Int, _:Int)          调用foo(2,3), 相当于调用sum(1,2,3) 两个_分别对应函数sum对应位置的参数.        用处:当你在代码中需要多次调用一个函数, 而其中的某个参数又总是一样的时候, 使用这个可以少敲一些代码(5)柯里化函数中的偏应用函数定义def sum(a:Int)(b:Int)(c:Int) = a + b + c; // (a: Int)(b: Int)(c: Int)Intval result = sum _ //柯里化赋值,结果是部分应用函数 Int => (Int => (Int => Int)) = <function1>sum(1)(2)(3)    //6result(1)(2)(3) //6result(1)(_: Int)(3) //部分应用函数:Int => Int = <function1>2018/4/5

6.面向对象

1) 类和对象

    (1) 简介scala中的类和java中的类一样,都是通过class定义class Person { //不写public,默认public//var name:String;  //报错,变量必须要被初始化,而java不需要被初始化,系统会自动赋初值var name :String = null //正确var age :Int = _    //正确,不知道赋上面值时,用_占位符}(2)创建对象var p1 = new Person()var p2 = new Person //没有参数,可以省略()(3) 类成员访问p1.name = "zhang3"  //设置,底层调用的是p1.name_=("zhang3"),其中_=是方法println(p1.name)    //取值非要用getter和setter,属性前加入 @BeanProperty(导入包:scala.beans._)(4) 单例对象scala中不支持静态成员的语法,通过单例对象实现object Test {private var id:Int = 0def m() ={id += 1id}}测试:scala>Test.m    //1scala>Test.m    //2(5) 伴生对象和伴生类单例对象和类如果同名的话,单例对象也叫伴生对象。例:class A {}object A {}伴生对象和伴生类可以互相访问,即使是private也可以访问,但是private[this]不能访问一个文件可以有多个类(6) apply方法object Dog {def apply():Unit = {println(1)}def apply(name:String):Unit = {println(2)}def main(args: Array[String]) {             var d1 = Dog()  //调用Apply()方法var d2 = Dog("hello") //调用Apply(String)方法}}

2) 主构造方法

    (1)定义每个类都有主构造方法,参数放在类名后,构造方法和类交织在一起。class Student(var name:String, var age:Int) 反编译代码:public class Student {private String name;private int age;public Student(String name, int age) {println("hello:" + name)this.name = name;this.age = age;}//getter和setter//name()和name_$eq(String)//age()和age_$eq(int)@Overridepublic String toString() {return name + ":" + age}} Student s = new Student();System.out.println(s) //打印s,就是打印s.toString()例:class Student(var name:String, var age:Int) {println("hello")    //加在主构造方法中override def toString = name + ":" +age}var s = new Student()println(s)(2) 带有默认参数的主构造方法构造方法可以带有默认参数。class Student(var name:String, var age:Int, val gender:String="female") {println("执行主构造方法")}var s1 = new Student("zhang3", 18, "male") //正确var s2 = new Student("li4", 18) //正确s2.name = "wang5"s2.gender = "male"(3) 私有构造方法class Student private(var name:String, var age:Int)var s = new Student("li4", 18)//报错

3) 辅助构造方法

    (1) 非主构造方法,方法名用this(2) 非主构造方法,也可以有默认值class Dog(val id:String) {var name :String = "大黄"def this(id:String,name:String) {this(id) this.name = name}override def toString = name + ":" + id}//测试var d1 = new Dog("1111")var d2 = new Dog("2222","二黄")println(d1)println(d2)

4) 继承和多态

    (1) 继承用extendsclass Person(var name:String, var age:Int)//没有写var,表示继承父类的属性class Student(name:String,age:Int, var no:String) extends Person(name,age)//测试new Person("tom", 18)new Student("jack",19,"123")Student从父类继承name和age,所以前面不要加变量var或者val,no是新加的元素,所以需要var(2) 多态多种形态,动态绑定,在执行期间确定引用对象的实际类型,根据其实际类型调用相应的方法,也就是子类可以赋值给父类。·   class Human(var name:String, var age:Int) {def walk():Unit = {println("walk in Human")} }class Teacher(name:String,age:Int) extends Human(name,age) {override def walk():Unit = {println("walk in Teacher")} }class Doctor(name:String,age:Int) extends Human(name,age) {override def walk():Unit = {println("walk in Doctor")} }//测试var x:Human = new Teacher("tom", 18)var y:Human = new Doctor("jack", 19)x.walk  //walk in Teachery.walk //walk in Doctor

5) 成员访问控制

    private 类内+伴生对象protected 同包+子类不写:默认是public,都可以访问特别之处(1)  private[this] 只能类内访问class Person {private[this] var name:String = "zhang3"    //只能类内private var age: Int = 18   //类内+伴生对象}object Person {def main(args:Array[String]) {var p = new Personprint(p.age) //18//print(p.name) //报错}}(2) 主构造方法也可以加入成员访问控制class Person(private var name:String, protected var age:Int)

6) 抽象类

    不能能被实例化的类。可以有抽象方法,非抽象方法,成员变量。但是scala增加了抽象成员变量。abstract class Person {var name:String //抽象成员变量def walk        //抽象方法}//子类如果继承,必须要实现抽象变量和抽象方法,如果不想实现,子类也需要是抽象类class Student extends Person {override var name:String = _            //覆盖父类的抽象变量override def walk():Unit = {println("walk in Student")} //覆盖父亲的抽象方法}

7) 内部类和内部对象

    定义在对象或者类内部的类object Ex extends App {class Student(var name:String, var age:Int) { //内部类class Grade(var name:String)//内部对象object Utils {def print(name:String) = println(name)}}object Student {//内部类class Printer {def print(name:String) = println(name)}}var s = new Student("tom", 18)//var grade = new Student.Grade("xxx")  //此处出错,怎么纠正?s.Utils.print("student:util.print(String)")new Student.Printer().print("Student.Printer().print(String)")}

8) 匿名类

    没有名字的类,一般用在某个类只在代码出现一次abstract class Person(var name:String, var age:Int) {def print():Unit}//调用//var p = new Person("tom", 18) //错误,抽象类不能new,也就是不能创建实例var p = new Person("tom", 18) {def print():Unit = println("hello")}p.print();

9) trait(特质),其实就是接口,相当于jdk1.8的接口,比jdk1.8以下版本的接口多了非抽象的变量和方法

        (1) scala没有提供接口interface,而用trait关键字,其实和接口等价。使用方法:extends或with,第一个实现的特质用extends,之后的用with它和抽象基本一样,可有抽象成员,抽象方法,具体成员和具体方法例:trait Closeable {def close():Unit}trait Clonable {def open():Unit}//第一个接口用extends,后面的用withclass File(var name:String) extends Closeable with Clonable{def close():Unit = println("file close")def open():Unit = println("file open")}//写一个全的traittrait Book {var a : Long = _    //具体成员var b : Long        //抽象成员def add(x:Int)      //抽象方法def add2(x:Int):Int = x+2   //具体方法}var b = new Book(){ //定义匿名内部类,只需要实现抽象方法和抽象成员变量即可override var b : Long = 1def add(x:Int) = println(x)}b.add(6)println(b.add2(5))

10) 自身类型(self type)

    trait A {val a = 1}trait B {this:A=>        //引入接口A,相当于把A的东西全放进来var b = 2def xx() {println(this.a + ":" + this.b)}}class C extends B with A//调用new C().xx()//还有一种特殊用法,this定义别名class D {self=>  //为this定义别名self,也可以是其他名字var x = 2def foo = self.x + this.x}//常见用法,用在内部类引用外部类的变量class OuterClass {xx=>    //为this定义别名var value = "here"class InnerClass {println(xx.value)}}

7.包

1) 包定义

    (1) 第一种定义方式,和java很像,package cn.cda.day1(2) 第二种定义方式package cn{package cda {package day1 {class Teacher {}}package day2 {class Student}}}以上方式不推荐

2) 作用域

    scala中有private,proteced和默认(public)外,还有private[x]和protected[x],其中x可以是包/类/单例对象

3) 包对象

    通过package关键字声明的对象为保对象,主要用于对常量和工具函数的封装,通过包名引用。package object Math {val PI = 3.14}class Test {def main(args:Array[String]) {m(3)    //3.14*9=28.62}def m(r:Double) = Math.PI * r * r}

4) import

    导入包下的所有的类和对象,还可以引入重命名和类隐藏等功能。1) 隐式导入默认导入的包,通过下面命令查看scala>:import2) 引入重命名import java.util.{HashMap=>JavaHashMap}import scala.collection.immutable.HashMapvar map = new JavaHashMap3) 类隐藏引入java.util.下的所有类,但是不想要HashMapimport java.util.{HashMap=>_,_} //隐藏HashMapimport scala.collection.immutable.HashMapvar map = new HashMap

8 模式匹配

1) 简介

    模式匹配类似switch语言,简单用法就是替代多层的if else语句和类型检查和快速匹配。它使用了关键字match来替换switch,一旦匹配到了,后面不再执行,所以不用break语句。scala有一个十分强大的模式匹配机制,可以用到很多场合。如switch,类型检查等,格式:case 变量: 类型=> 代码例:java和scala进行比较 --javafor (int i = 1; i < 5 ; i++) {switch (i) {case 1:System.out.println(1);break;case 2:System.out.println(2);//不带break会陷入其它分支,同时输出2,3case 3:System.out.println(3);break;default:System.out.println("default");//case语句不能接表达式//case i%5==0:System.out.println("10")}}--scalafor (i <- 1 to 5) {i match {case 1 => println(1)        //不需要写break,case 2 => println(2)case 3 => println(3)                case _ => println("default")}}//上面的case语句中,还可以加入表达式for (i <- 1 to 5) {i match {case 1 => println(1)        //不需要写break,case x if (x%2 == 0) => println(s"$x 是偶数")     //加入表达式 ,此时的x是形参,i是实参   case _ =>   //这句话表示其它任何情况都不进行操作}}//还可以作为函数体def m(x:Int) = x match {case 5 => "整数5"case y if (y % 2 == 0) => "能被2整除"  //注意y认为是形参case _ => "其它整数"}println(m(5)//反编译:public String m(int x){switch (x){default: tmpTernaryOp = "其它整数"; break;}return  x % 2 == 0 ? "能被2整除" : "整数5";"}  

2) 模式匹配的7大类型

    (1)常量模式case后面接的全部是常量例:for (i <- 1 to 5) {i match {case 1 => println(1)        //不需要写break,case 2 => println(2)case 3 => println(3)                case _ => println("default")//可以写成 case x}}(2)变量模式case后面接的是变量例:def m(i:Int) = i match {case x if (x % 2 == 0) => "能被2整除"       //这个顺序是有关系的case x if (x % 3 == 0) => "能被3整除"   case x => "能被2或3意外的数"   // 等价于 case _}//调用println(m(5))println(m(4))println(m(3))   (3)构造方法模式与创建对象相反,见下例1case class Dog(val name:String, val age:Int)def m(x:AnyRef) = x match {case Dog(name,age)=>println(name+":"+age)// 构造函数模式,与创建对象相反,对对象进行析构,调用unapply方法,普通类没有,case类系统会生成。case _=>}//测试val dog = Dog("Pet", 2) //调用apply创建对象m(dog)例2:对部分变量析构case class Dog(val name:String, val age:Int)def m(x:AnyRef) = x match {case Dog(_,age)=>println(age) //表示匹配这个成员域,但是不需要使用nam的值case _=>}(4)序列模式用于匹配Seq集合的,用法和上面类似,但是可以使用_*来匹配多个元素,并且只能放在模式内的最后例:def m(x:AnyRef) = x match {case Array(a,b)=>println("1")case Array(a,_,b,_*)=>println("2")  //_匹配第2个元素,_*匹配任意多,只能放模式最后case _=>}//调用 m(Array(1,2,3,4))(5)元组模式和上面用法相似,但是不能使用_*,_*只能在序列模式中使用。例:def m(x:AnyRef) = x match {case (a,b)=>println("1")case (a,_,b,_)=>println("2")//case (a,_*)//元素模式不能使用_*case _=>}var t = (1,2,3,4)m(t)(6)类型模式匹配变量的类型class Aclass Bclass C extends Adef m(x:AnyRef) = x match {case y:String=>println(1)case y:B=>println(2)case y:A=>println(3)case _=>println(4)}//测试val b = new Bval c = new Cm("hello")m(b)m(c)反编译源代码  public void m(Object x){if ((x instanceof String)){this.println(1);}else if ((x instanceof B)){this.println(2);}else if ((x instanceof A)){this.println(3);}else  {this.println(4);}}(7)变量绑定模式如果想要的不是析构对象,而且返回匹配模式的对象,很常用例1case class Dog(val name:String,val age:Int){override def toString=name+":"+age}def m(x:AnyRef) = x match { //Dog(_,_)用于匹配输入对象中包括两个成员变量的Dog对象,匹配成功后把对象赋值给dcase d@Dog(_,_) => println("变量绑定模式返回的变量值:" + d)case _=>}// 测试val dog = new Dog("Pet", 2)m(dog)反编译源代码:public void m(Object x) {if ((x instanceof Dog)){Dog d = (Dog)x;this.println("变量绑定模式返回的变量值:" + d)}else   {}}例2:更常见,也更复杂val list = List(List(1,2,3,5),List(4,5,6,7,8,9))def m(x:AnyRef) = x match {//变量绑定模式case e1@List(_,e2@List(4,_*))=>println("e1:" + e1 + ",e2:" + e2)case _=>}//调用 m(list)//e1:List(List(1, 2, 3, 5), List(4, 5, 6, 7, 8, 9)),e2:List(4, 5, 6, 7, 8, 9)---反编译代码:public void m(Object x)  {              if ((x instanceof List)){List e1 = (List)x;Some localSome1 = List..MODULE$.unapplySeq(e1);if ((!localSome1.isEmpty()) && (localSome1.get() != null) && (((LinearSeqOptimized)localSome1.get()).lengthCompare(2) == 0)){Object e2 = ((LinearSeqOptimized)localSome1.get()).apply(1);if ((e2 instanceof List)){List localList2 = (List)e2;Some localSome2 = List..MODULE$.unapplySeq(localList2);if ((!localSome2.isEmpty()) && (localSome2.get() != null) && (((LinearSeqOptimized)localSome2.get()).lengthCompare(1) >= 0)){Object localObject2 = ((LinearSeqOptimized)localSome2.get()).apply(0);if (BoxesRunTime.equals(BoxesRunTime.boxToInteger(4), localObject2)){Predef..MODULE$.println(new StringBuilder().append("e1:").append(e1).append(",e2:").append(localList2).toString());localBoxedUnit = BoxedUnit.UNIT; return;}}}}}}

3) 正则表达式与模式匹配(略)

    (1)Scala正则表达式       (2)正则表达式在模式匹配中的应用

4) for循环种的模式匹配

    (1)变量模式匹配for((x,y)<-Map("a"->1,"b"->2,"c"->3)) {println(x + ":" + y)}(2) 常量模式匹配//下面只有"b"被匹配到,输出2for(("b",y)<-Map("a"->1,"b"->2,"c"->3)) {println(y)}(3) 变量绑定模式匹配//可以绑定变量xxx和yyyfor((xxx@"b",yyy@y)<-Map("a"->1,"b"->2,"c"->3)) {println(xxx + ":" + yyy)}(4) 类型模式匹配//类型value为字符串才能匹配到for((x,y:String)<-Map("a"->1,"b"->"hello","c"->3)) {println(x + ":" + y)}(5) 构造方法模式匹配case class Dog(val name:String, val age:Int)case class Cat(val name:String, val age:Int)for (Dog(name,age) <- List(Dog("a",1),Cat("b",2),Dog("c",3))) {println(name + ":" + age)}上面输出第1个和第3个for (List(first,_*) <- List(List(1,2,3), List(4,5,6,7))) {println(first)}(6) 序列模式匹配可以用_*

5) 样例类和样例对象

    样列类(case class):使用case修饰的类。就是增加了一些方法,比如unapply。用在上面的模式匹配.   1) 样例类:是一种特殊的类,可以用于模式匹配。case class是多例,case object是单例。上面已经做了一个例子了,下面再做一个例子,用到了sealted.trait中前面加入 seatled,表示密封类a) 其修饰的trait,class只能在当前文件里面被继承b) 并且用sealed修饰这样做的目的是告诉scala编译器在检查模式匹配的时候,让scala知道这些case的所有情况,scala就能够在编译的时候进行检查,看你写的代码是否有没有漏掉什么没case到,减少编程的错误。例:sealed trait Acase class B(id:String,name:String) extends Acase class C(id:String) extends Acase class D(id:String) extends Adef m(x:A) = x match {case B(id,name)=>"1"case C(id)=>"2"     // 这一行如果不写,系统会警告,这样的好处是提示你不要漏了case D(id)=>"3"} //测试val b = new B("1","zhang3")println(m(b))// 注意,如果注释掉上面的B,C,D中的任何一句,系统会警告,所以在子类众多的时候,要用 sealed修饰带来的好处。2) 样例对象(case object)上面看到每个子类都有自己的属性,但是实际开发,可能不需要属性,如果不定义属性,编译器会警告。这时候需要定义样例对象(case object)来声明sealed trait Acase class B(id:String,name:String) extends Acase class C(id:String) extends Acase class D(id:String) extends Acase object E extends Adef m(x:A) = x match {case B(id,name)=>"1"case C(id)=>"2"     case D(id)=>"3"case E=>"4"} //测试val b = new B("1","zhang3")println(m(b))println(m(E)) //直接调用分析:a)case class会先创建对象,而case object可以直接使用b)case class会生成两个字节码文件,而case object是一个c)case class生成的伴生对象会自动实现 apply和unapply方法,而case object不会使用 case object可以提高速度,减少开销 例2:spark中的一段代码如下,看学生是否看懂?import scala.util.Randomcase class SubmitTask(id: String, name: String)case class HeartBeat(time: Long)case object CheckTimeOutTask    //定义样例对象object Test extends App {var arr = Array(CheckTimeOutTask, HeartBeat(2333), SubmitTask("0001", "task-001"));arr(Random.nextInt(arr.length)) match {case SubmitTask(id, name) => { println(s"$id,$name") }case HeartBeat(time) => { println(time) }case CheckTimeOutTask => { println("check") }}3) Option类型Option类型也是样本类,表示值是可选的,要么无值,要么有值,Option的子类有Some和None用Some(x) 表示有值,x是真正的返回值用None表示无值val map = Map("cn"->1,"jp"->2)      val v = map.get("cn") match {   //get方法返回 Option类型case Some(i) => icase None => 0}查看map集合的源代码: def get(key: A): Option[B]查看some的源代码:case class Some[+A](x: A) extends Option[A] 查看None的源代码:case object None extends Option[Nothing] {我们常用 getOrElse("c",0)

9 隐式转换

1)隐式转换简介

    scala提供的一种强大的语法特征,必须掌握。开发中,会自动转换。scala定义了一些隐式转换,会自动导入他们。比如 1 to 5 调用 1.to(5),但是to并不是Int类型的方法,它会自动转换为 scala.runtime.RichInt源代码:系统自动导入Predef对象,在scala.Predef中,objectPredef父类LowPriorityImplicits中方法intWrapper(x:Int)=new runtime.RichInt(x)不仅如此, Int还可以转换为其它类型(AnyRef,Integer,Double,Float,Long),可以由其它类型转换而来查看所有的隐式转换scala>:implicit -vscala.Int的伴生对象包含了Int到其它类型的转换implicit def int2long(x:Int) : Long = x.toLongimplicit def int2float(x:Int) : Float = x.toFloatPredef对象中也可以了大量的隐式转换函数,如Scala数值类型到java数值类型的转换implicit  def byte2Byte(x:Byte) = java.lang.Byte.valueOf(x)正是这些隐式转换函数的存在,简化了Scala代码。       

2) 隐式转换

    (1)隐式转换函数Scala默认提供了大量的隐式转换,比如Int到Float,但是如果想实现Float到Int,需要自己定义例:val value : Int = 1.0f  // 报错修改:implicit def m(x:Float) = x.toInt   //toInt方法有,但是没有隐式转换val value : Int = 1.0f原理:当编译机发现类型不匹配,就会查找隐私转换函数--------xjad反编译-----------  public int m(float x){return (int)x;}int value = m(1.0F);System.out.println(value);          }注:名称可以是任意(与参数类型和返回值有关),但不要重复,否则隐式转换报错,不过尽量给名字写的有意义(2) 隐式类隐式类的转换不像隐式转换函数那么明显。例;implicit class A (val name:String) { def bark = println(name + " is barking")}//调用"Nacy".bark //由于String没有 bark方法,因此会找隐式类,由于A的主构造方法是String,就会调用。---源代码          public static class Test$A{private final String name;public Test$A(String name) {this.name = name}public void bark(){System.out.println(name + " is barking");}}           public final class Test${public void main(String args[]){new Test.A("Nacy").bark();//把“nacy”转换为创建A的对象}}(3) 隐式对象单例对象前加入implicit关键字trait A[T] {def m(x:T):T    }//隐式转换对象:整数的平方implicit object AInt extends A[Int]{def m(x:Int) = x * x}//隐式转换对象:字符串的乘积implicit object BString extends A[String] {def m(x:String) = x * 2}//定了一个函数:函数具有泛型参数def foo[T:A](x:T) = {val obj = implicitly[A[T]] //通过 implicitly方法,知道T的类型,创建A的相应子类对象obj.m(x)}//调用println(foo(5)) //25,从下面源代码可以看到,翻译成java时传递两个参数println(foo("5"))//"55"------源代码----public final class Test${public Object foo(Object x, Test.A o)   { //传递A的子类对象Test.A obj = (Test.A)(o);return obj.m(x);}public void main(String args[])         {foo(5,传递Test.AInt的单例对象);}}public final class Test{interface A{Object m(Object obj);}}public static class AInt implements A{public int m(int x){    return x * x;   }}public static class BString implements A{public String m(String x){ return x * 2}}(4) 隐式参数 上面的implicitly方法换一种形式,定义在参数中 , 参数前加了implicit,这种形式的参数成为隐式参数上面代码可以化简如下:def foo[T:A](x:T)(implicit obj:A[T]) = { //知道T的类型,创建A的相应子类对象obj.m(x)}//编译后的源代码基本不变(5) 隐式值隐式值也叫隐式变量,前面用implicit修饰例1:implicit val x : Double = 2.55def sqrt(implicit y: Double) = Math.sqrt(y)//测试 scala> sqrt //不指定参数,编译器再当前作用于查找相应的隐式值或隐式对象,找到x传给它--xjad反编译public final class Test${private final double x = 2.5499999999999998D;   public double sqrt(double y) {return Math.sqrt(y);}public void main(String args[]){sqrt(x);}}例2:改写上面的代码:trait A[T] {def m(x:T):T    }class AInt extends A[Int]{ //普通类def m(x:Int) = x * x}class BString extends A[String] {def m(x:String) = x * 2}implicit val a = new AInt   //隐式值,上面的例子是隐式对象implicit val b = new BStringdef foo[T:A](x:T)(implicit obj:A[T]) = { obj.m(x)}//调用println(foo(5)) //25println(foo("5"))//"55"

3) 隐式参数使用常见问题

    1. 当函数没有柯里化,implicit关键字组用于函数列表中的所有参数scala>def m(implicit x:Double,y:Double) = x * y     //所有参数都作用implicitm: (implicit x: Double, implicit y: Double)Doublescala>implicit val d = 2.5scala>m //结果 6.252. 隐式函数使用时要么全部指定,要么全不指定,不能只指定部分如果上面调用scala>m(3.0) 就报错scala>m(3.0,3.0)3. 同类型的隐式值只在当前作用域内出现1次如果再定义 scala>implicit val d2 = 3.5scala>m // 报错 4. 在定义隐式函数时,implicit关键字只能在参数开头//报错,不能定义在第2个参数def m(x:Double,implicit y:Double) = x * y   5. 如果想达到函数def m(x:Double,implicit y:Double)只将参数y定义为隐式函数的目的,需要对函数柯里化//柯里化后,只有参数y是隐式参数def m(x:Double)(implicit y:Double) = x * yimplicit val d = 4.0m(3)6. 柯里化的函数implicit关键字只能作用于最后一个参数def m(x:Double)(y:Double)(implicit z:Double) = x * y * z //正确def m(implicit x:Double)(y:Double)(z:Double) = x * y * z //错误,没有作用于最后一个 7. implicit关键字只在隐式参数中出现1次,对柯里化的函数也不例外def m(implicit x:Double,implicit y:Double) = x * y // 错误8. 匿名函数不能使用隐式参数val m = (x:Double, y:Double)=>x * y // 正确val m = (implicit x:Double, y:Double)=>x * y9. 柯里化的函数如果有隐式参数,则不能使用其偏应用函数def m(x:Double)(y:Double) = x * yval t1 = m _    //赋值给t1, 定义两个参数的偏函数t1(3,0)(4,0)val t2 = m(3.0) _t2(4.0)以上都没有问题,但是如果下面有隐式参数,则会报错 def m(x:Double)(implicit y:Double) = x * yval p = m _ //报错

4)隐式转换规则与问题

    (1) 隐式转换的若干规则a) 作用域规则必须在当前作用域才能起作用。c) 无歧义规则不能存在两个一样功能的隐式转换函数。d) 一次转换原则只经过1次隐式转换,不能经过多次(2) 是否调用隐式转换非必要的情况下,尽量少用,如果是为了炫耀,大胆使用。

10 类型参数

1) 简介

    (1) 简介在类的声明中,定义一些泛型,然后在类内部,就可以使用这些泛型类型。scala泛型和java泛型基本相同,只是Java语法格式为<>,而Scala语法给是为[]//比如: java中List<T> ,而Scala中为 List[T]//比如:trait Map[A,B] extends Iterable[(A,B)] with GenMap[A,B] with scala.collection.Map[A,B] {override def empty:Map[A,B] = Map.empty}      (2) 泛型类class Person[T](var name :T)class Student[T,S](name:T, var age:S) extends Person(name)//name前不写var表示继承例:新生入学,填写id时候,有的人用整数,有的人用字符串class  Student[T](val id:T) {def get(hukouId:T) = id + ":" + hukouId}val a = new Student[Int](111)a.get(4)val a = new Student(111) //不写Int,可以自动推断val a = new Student[String]("111")//测试class Student[A,B](var name:String, var age:Int)println(new Student[String,Int]("a",1).name)(3) 泛型方法与泛型类类似,给某个函数在声明时指定泛型类型def getCard[T](content: T) = {if (content.isInstanceOf[Int]) 1        //等价于java的instanceOfelse if (content.isInstanceOf[String]) 2else 3}//测试getCard(111)        //1getCard("222")      //2getCard(false)      //3(4) 类型通配符在java中,采用List<?>来做,但是scala中,没有采用上面的特性,是通过存在类型来解决类[T,U,..] forSome {type T;type U;...}例://存在类型Array[T] forSome {type T}def printAll(x : Array[T] forSome {type T}) = {for (i <- x) {println(i)}}---源代码:public void printAll(Object x)              {Predef$.MODULE$.genericArrayOps(x).foreach(new Serializable() {public final void apply(Object i)                       {System.out.println(i);}});}//可以写简化形式def printAll(x : Array[_]) = {for (i <- x) {prntln(i)}}           

2) 类型变量界定

    对泛型范围进行界定,而不是任意类型。比如必须是某个类的子类,或者是父类,才能正常使用。java中,这么定义://List<? extends Object> 接收object的子类,包括Object//List<? super Integer> 接收Integer的父类,包括Integerscala没有采用,它采用对应<:>:例1:class Person(val name: String) {def makeFriends(other: Person) = println(this.name + "和" + other.name + "交朋友")}class Student(name: String) extends Person(name)class Party[T <: Person](p1: T, p2: T) {def play = p1.makeFriends(p2)}//调用var p1 = new Student("zhang3")var p2 = new Student("li4")new Party[Student](p1, p2).play例2: def compare[T <:Comparable[T]](first:T,second:T) = {//表示Comparable的子类if (first.compareTo(second)>0) firstelsesecond}调用;:compare("A,"B”) //B

3) 视图界定

    用<%表示: 相当于上面的<:加上隐式转化class Person(val name: String) {def makeFriends(other: Person) = println(this.name + "和" + other.name + "交朋友")}class Teacher(var name: String)class Party[T <% Person](p1: T, p2: T) {def play = p1.makeFriends(p2)}implicit def teacher2Person(t: Teacher) : Person = new Person(t.name)//调用var p1 = new Teacher("zhang3")var p2 = new Teacher("li4")new Party[Teacher](p1, p2).play

4) 上下文界定

    回顾以前:>: 继承:要求是长辈<: 继承:要求是低辈<% 继承+隐式转换 这次T:A   T是一个泛型, A是个类,要求调用这个类的函数时,必须要隐式引入A[T]。举个例子:T是整数Int,A是Ordering(理解成排序comparator,系统有这个类),要求使用时候要引入隐式值Ordering[Int]class Test[T:Ordering](val a:T,val b:T) {def bigger(implicit myComparator:Ordering[T]) {if (myComparator.compare(a,b)>0)println(a +":"+ myComparator.getClass)elseprintln(b)}}new Test(1,2).bigger    //2----反编译----public class Test{private final Object a;private final Object b;public Test(Object a, Object b,){this.a = a;this.b = b; }public void bigger(Ordering myComparator){if (myComparator.compare(a(), b()) > 0)System.out.println(a());elseSystem.out..println(b());}}new Test(1,2).bigger(系统自带的实现Int的Ordering对象)     

5) 多重界定

    (1) T:A:B  隐式引入A[T],B[T](2) T<%A<%B 存在T到A,T到B的隐式转换(3) T1>:T<:T2 T1是T类型的超类,T2也是T类型的超类class A[T]class B[T]implicit val a = new A[String]implicit val b = new B[String]//1.当前作用域中,必须存在两个隐式值,类型为 A[T],B[T]def test[T:A:B](x:T) = println(x)  test("测试1")implicit def t2A[T](x:T) = new A[T]implicit def t2B[T](x:T) = new B[T]//2.当前作用域中,必须存在T到A,T到B的隐式转换def test2[T <% A[T] <% B[T]](x:T) = println(x)test2("测试2")

6) 协变与逆变

    //解决问题,如果Child是Father的子类,那么List<Child>是不是List<Father>的子类,答案:不是,但这会造成很多问题。但Scala只要灵活运用协变与逆变,就可以解决这个问题协变 +T  当A是B的子类, 那么func(A) 是func(B)的子类例:class Fatherclass Child extends Fatherclass Test[+T]var x = new Test[Father]var y = new Test[Child]//此事,x也是y的父亲x = y   //正确y = x //错误逆变 -T当A是B的子类, 那么func(A) 是func(B)的父类

===========================================================================
11 scala并发编程基础(讲义已经单独做成doc文档:讲义-Actor编程.docx)
1) 简介
(1) 并发和并行
并发:在一台处理器上“同时”处理多个任务,一个时刻只有一个任务跑
并行:在多台处理器上同时处理多个任务,一个时刻有有个任务跑。

    优化:并发:增加进程或者线程,纵向扩展并行:增加cpu,横向扩展Actor模型:可以同时解决纵向和横向扩展

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293081.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win7 64位下如何安装配置mysql-5.7.4-m14-winx64(安装记录)

1. mysql-5.7.4-m14-winx64.zip下载 官方网站下载地址&#xff1a;http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.17-winx64.zip 2、解压到D:\mysql.&#xff08;路径自己指定&#xff09; 3、在D:\mysql\mysql-5.7.4-m14-winx64下新建my.ini配置文件 内容如下&am…

Android之ndk之gdb调试

https://code.google.com/p/android/issues/detail?id152832

使用插件创建 .NET Core 应用程序

使用插件创建 .NET Core 应用程序本教程展示了如何创建自定义的 AssemblyLoadContext 来加载插件。AssemblyDependencyResolver 用于解析插件的依赖项。该教程正确地将插件依赖项与主机应用程序隔离开来。将了解如何执行以下操作&#xff1a;构建支持插件的项目。创建自定义…

支持向量机SVC

原文&#xff1a; http://ihoge.cn/2018/SVWSVC.html 支持向量机(support vector machine)是一种分类算法&#xff0c;但是也可以做回归&#xff0c;根据输入的数据不同可做不同的模型&#xff08;若输入标签为连续值则做回归&#xff0c;若输入标签为分类值则用SVC()做分类&…

Shell 控制并发

方法1: #!/bin/bash c0 for i in seq -w 18 31;dowhile [ $c -ge 3 ];doc$(jobs -p |wc -w)sleep 1sdonebash run_cal_us_tmp.sh 201407$i &#echo "sleep 5shaha" &c$(jobs -p |wc -w) done优点&#xff1a;实现简单 缺点&#xff1a;若sleep 时间较短&…

Android之严苛模式(StrictMode)

Android 2.3提供一个称为严苛模式&#xff08;StrictMode&#xff09;的调试特性&#xff0c;Google称该特性已经使数百个Android上的Google应用程序受益。那它都做什么呢&#xff1f;它将报告与线程及虚拟机相关的策略违例。一旦检测到策略违例&#xff08;policy violation&a…

Shell 脚本——测试命令

********************************************一、测试命令简介二、测试结构三、整数比较运算符四、字符串运算符五、文件操作符六、逻辑运算符********************************************一、测试命令简介Shell中存在一组测试命令&#xff0c;该组测试命令用于测试某种条件…

如何通过 C# 将文本变为声音 ?

咨询区 user2110292我的项目有一个需求需要将可以将 文本 转化为 声音&#xff0c;请问大家是否有开源的 C# 库 来解决这件事情&#xff1f;回答区 HABJAN最近 Google 发布了一个开源的 Google Cloud Text To Speech 包&#xff0c;.NET版本的github链接&#xff1a;https://gi…

sklearn集合算法预测泰坦尼克号幸存者

原文&#xff1a; http://ihoge.cn/2018/sklearn-ensemble.html 随机森林分类预测泰坦尼尼克号幸存者 import pandas as pd import numpy as npdef read_dataset(fname):data pd.read_csv(fname, index_col0)data.drop([Name, Ticket, Cabin], axis1, inplaceTrue)lables …

Oracle数据库案例整理-Oracle系统执行时故障-Shared Pool内存不足导致数据库响应缓慢...

1.1 现象描写叙述 数据库节点响应缓慢&#xff0c;部分用户业务受到影响。 查看数据库告警日志&#xff0c;開始显示ORA-07445错误&#xff0c;然后是大量的ORA-04031错误和ORA-00600错误。 检查数据库日志&#xff0c;数据库仍处于活动状态的信息例如以下&#xff1a; S…

C#读写txt文件的两种方法介绍

1.添加命名空间 System.IO; System.Text; 2.文件的读取 (1).使用FileStream类进行文件的读取&#xff0c;并将它转换成char数组&#xff0c;然后输出。 byte[] byData new byte[100];char[] charData new char[1000];public void Read(){try{FileStream file new FileStream…

Beetlex官网迁移完成

由于beetlex.io域名无法指向国内&#xff0c;使用国内的服务器很多时候有抽风情况出现&#xff0c;所以把网站迁回国内&#xff1b;新的域名也申请完成并且申请备案通过&#xff0c;现在可以通过https://beetlex-io.com来访问Beetlex的官网.接下把涉及的费用和部署情况也说一下…

linux之tail 命令

tail 命令从指定点开始将文件写到标准输出.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不但刷新,使你看到最新的文件内容. 1&#xff0e;命令格式; tail[必要参数][选择参数][文件] 2&#xff0e;…

SVM支持向量机绘图

原文&#xff1a; http://ihoge.cn/2018/SVM绘图.html %matplotlib inline import matplotlib.pyplot as plt import numpy as np class1 np.array([[1, 1], [1, 3], [2, 1], [1, 2], [2, 2]]) class2 np.array([[4, 4], [5, 5], [5, 4], [5, 3], [4, 5], [6, 4]]) plt.f…

Hibernate学习——建立一个简单的Hibernate项目

最近老师让做个web小应用&#xff0c;大三的时候学习过一点J2EE的东西&#xff0c;也做过一些web相关的XXX管理系统&#xff0c;都是用servlet&#xff0c;jsp这些完成的&#xff0c;虽然勉强能够完成任务&#xff0c;但其中各种代码掺杂在一起&#xff0c;不好看而且维护起来也…

python列表生成多个号码_python遍历多个列表生成列表或字典

原博文 2017-03-10 18:30 − key[a,b,c,d] value[1,2,3,4] mydictdict(zip(key,value)) print mydict 输出结果&#xff1a; {a: 1, c: 3, b: 2, d: 4} 也可以用zip同时遍历多个列表&#xff0c;生成一个多维列表 key... 相关推荐 2019-12-18 21:27 − 一.zip函数描述和使用 zi…

Cisco 胖AP和瘦AP的区别

无线接入点&#xff08;AP&#xff0c;Access Point&#xff09;也称无线网桥、无线网关&#xff0c;也就是所谓的“瘦”AP。此无线设备的传输机制相当于有线网络中的集线器&#xff0c;在无线局域网中不停地接收和传送数据&#xff1b;任 何一台装有无线网卡的PC均可通过AP来…

linux之head命令

head 与 tail 就像它的名字一样的浅显易懂&#xff0c;它是用来显示开头或结尾某个数量的文字区块&#xff0c;head 用来显示档案的开头至标准输出中&#xff0c;而 tail 想当然尔就是看档案的结尾。 1&#xff0e;命令格式&#xff1a; head [参数]... [文件]... 2&#xf…

NCC CAP 6.0 发布 —— 新增支持 OpenTelemetry

前言今天&#xff0c;我们很高兴宣布 CAP 发布 6.0 版本正式版&#xff0c;在这个版本中&#xff0c;我们主要致力于对 OpenTelemetry 提供支持&#xff0c;以及更好的适配 .NET 6。那么&#xff0c;接下来我们具体看一下吧。总览可能有些人还不知道 CAP 是什么&#xff0c;老规…

朴素贝叶斯--文档分类

原文&#xff1a;http://ihoge.cn/2018/MultinomialNB.html 把文档转换成向量 TF-IDF是一种统计方法&#xff0c;用以评估一个词语对于一份文档的重要程度。 TF表示词频&#xff0c; 即&#xff1a;词语在一片文档中出现的次数 词语总数IDF表示一个词的逆向文档频率指数&am…