Scala基础知识

0. Scala简介

  1. 多范式
  2. 类似java, 可调用Java类库, 运行于JVM
  3. 初衷是实现可伸缩的语言
  4. 集成面向对象编程和函数式编程的各种特性
  5. IDE选择idea

1. 入门

支持的数据类型

Scala中不存在基础数据类型,一律以类的形式出现

数据类型 含义
Byte 8位整数,-128~127
Short 16位整数,-32768~32767
Int 32位整数, -2147483648~2147483647
Long 64位整数, -9223372036854775808~9223372036854775807
Float 32位浮点数
Double 64位浮点数
Char 16位Unicode字符
String 字符序列
Boolean 布尔
Unit 空,同void,打印出()
Null null
Nothing 任何类的子类
Any 任何类的超类
AnyVal 任意常量类
Java类 可以通过import导入Java类库,引入Java数据类型如java.util.Date
BigInt math类下的子类,整数
BigDecimal math类下的子类,数值型

基础语法

代码 功能
var x:Int=1 定义一个可修改的变量x=1,类型为Int
val y=2 定义一个不可修改的常量y=2,类型由系统自己推断
printf(“x:%d”,x) 格式化打印,d数字,s字符串,f浮点数
var x,y=8 同时赋值8给x和y两个变量
x=x+1,x+=1,x.+(1) 等价,不支持x++
1 to 10 由1到10组成的集合
1 until 10 由1到9组成的集合
_ 表示全部,相当于*
import math._ 导入math类下所有子类
“hello”.apply(1) 将字符串看作集合,按索引1获取字符
“hello”.reverse 字符串反转
var x:BigInt=BigInt(“99999999999999999”) 通过BigInt方法转换字符串突破整数长度限制
var x=StdIn.readInt() 标准输入获取Int赋值给变量x
var r=Random.nextInt(20) 获取在0到20间的随机数
(x:Int,y:Int):Int=>x+y 推导

2. 数组

定长数组Array

//创建数组
var arr1=Array(1,2,3)//初始化赋值数组
var arr2=New Array[Int](3)//初始化指定元素为Int,长度为3不可变
//遍历数组
for(i<-arr1.indices)print(i)//i表示从1到arr1的长度为止的数字序列
//数组赋值
arr1(0)=10//赋值10给数组第一个元素
//数组的方法
var amax=arr1.max//数组最大值,其他聚合函数用法相同
var alen=arr1.length//数组长度
//map方法,遍历后yield
var aarr=arr1.map(_+1)//map相当于yield,过程为所有元素+1,返回新数组
//foreach方法,遍历无输出
arr1.foreach(printf _)//遍历打印
//过滤器
var newarr=arr1.filter(_%2==0)//满足过滤条件的元素生成新数组,_表示所有元素
//合并数组
var carr=concat(arr1,arr2)
//数组排序
var sarr=arr1.sorted
//字符串拆分后按长度排序
var sarr="aaa aa a aaaa".split("\\s").sortWith(_.length < _.length )
//reduceLeft方法,第一个元素和第二元素操作后的结果与第三个元素操作
var res=arr1.reduceLeft(_*_)//阶乘
//比较两个数组的所有元素
var flag=arr1.corresponds(arr2)(_.equals(_))//元素依次比对返回布尔
//zip方法,依次组合两个Range,返回Vector,两个Array,返回元组
    var a1=1 to 5
    var a2=2 to 6
    var a3=a1 zip a2//返回Vector((1,2), (2,3), (3,4), (4,5), (5,6))

变长数组ArrayBuffer

//创建和遍历数组的方法同Array
var arr=new ArrayBuffer[Int]()
//赋值
arr+=(1,2,3)
//在指定索引位置追加元素
arr.insert(0,10,20)//在0索引位置,追加10和20
//追加其他数组的元素
arr++=ArrayBuffer(4,5,6)
//截取元素
arr.trimStart(2)//前两个
arr.trimEnd(2)//后两个
//按索引删除
arr.remove(0)//删除第一个元素

3. 函数

  1. 简单函数的一般形式
    def 函数名(参数:类型):返回类型=函数体
  2. 函数的调用
    Object名.函数名()
  3. 匿名推导函数
    (x:Int,y:Int):Int=>x+y
    (x,y)=>x+y

基本函数

//基本形式,参数类型必须指定,返回类型可由系统自动推断
def madd(x:Double,y:Double)=x+y
//同类型参数传入多个,结合聚合函数求和,返回求和后数字
def fsum(x:Int*)=(for(i<-x)yield i).sum//*表示接收多个参数
//可指定参数名称并给定初始值,按名称传参
def func1(pname:String="ghy",page:Double=28)=println(pname+page)
//函数传入参数时可使用(数组:_*)形式拆分数组后传入
var sumarr=fsum(arr:_*)//表示传入数组arr的每个元素给自定义的求和函数

可变函数

//Scala支持函数赋值给变量,可实现函数指针功能
var f1=fsum _//空格_表示将该函数的功能全部赋值给变量f1
f1=func1 _//由于变量可修改,在方法中可随时指向新的函数

高阶函数

//定义一个函数,其中参数为匿名函数,可给定参数值
def dou(f:(Int)=>Int)=f(5)//对于传入的函数规定了参数类型,返回类型,参数的初始值为5
//调用该函数时要传入符合要求的另一个函数
var res=dou(x=>x+1)//参数为匿名函数(参数为x,函数体x+1,类型由系统推断)
//在数组中调用自定义函数
  def fang(n:Double)={
    var res=math.pow(n,n)
    println(res)
  }
(1 to 5).foreach(fang(_))//foreach表示遍历数组但不yield结果,调用fang函数传入_每个元素

闭包函数

  1. 定义的函数返回另一个函数,包装返回中的函数叫闭包
  2. 使用函数设计模式,导致闭包的函数能够在非作用域也能够被调用
//函数体中包含函数
def b1(x:Int)=(y:Int,z:Int)=>y*z+x
//调用函数返回闭包函数
var f1=b1(10)
var res=f1(10,10)

函数的柯里化

  1. 将多个参数转变为高阶函数形式的多个单参数函数的过程
  2. 便于使用lambda表达式
  def add(x:Int,y:Int)=x+y//双参数
  def add1(x:Int)=(y:Int)=>x+y//柯里化后闭包函数
  def add2(x:Int)(y:Int)=x+y//简写
//调用时可分布返回单参数函数
    var res1=add1(10)
    var r1=res1(5)
    var res2=add2 _
    var r2=res2(5)
    var r3=r2(10)
    println(r1,r3)

菲波那切数列

//定义一个函数fec,递归必须指定返回类型Int
def fec(n:Int):Int=if (n==0) 0 else if (n==1) 1 else fec(n-1)+fec(n-2)
//调用函数fec,循环打印前10个数
for(i<1 to 10)print(fec(i)+"\t")

4. 控制语句

while

var x=0
while(x>10){
print(x)
x += 1
}

if

var s=if(x>10) "yes" else if (x<5) "no" else "ok"//if判断后返回字符串给s

for

//集合遍历,yield弹出1到10返回赋值给s
var s=for(i<-1 to 10)yield i
//双层for循环,守卫条件i==j
for(i<-1 to 5;j<-1 to 5 if i==j)printf("i:%d,j:%d",i,j)
//集合反转,可实现10 to 1的降序序列
for(i<-(1 to 10).reverse)print(i)

杨辉三角

//创建数组
var martix=Array.ofDim[Int](6,6)
//赋值数组
for (i<-martix.indices;j<-0 to i)if (i==0|j==0|i==j) martix(i)(j)=1 else martix(i)(j)=martix(i-1)(j-1)+martix(i-1)(j)
//打印数组
for (i<-martix.indices;j<-0 to i){printf("%4d",martix(i)(j));if (i==j)println()}

5. 集合

分类

  1. 可变集合,支持修改扩展元素
  2. 不可变集合,修改后会返回新集合,不影响原集合
集合类型 特点 常用
Seq 保证插入顺序,可重复 IndexedSeq
Set 不保证顺序,不可重复 SortedSet
Map 键值对,排序时按键排序 SortedMap
Vector 树形结构的索引序列,不可变 1 to 10
Range 索引序列 Range 1 to 10
列表 Seq序列,元素类型相同,不可变 List
元组 小括号形式 (1,”one”)
迭代器 可迭代 iterator

6. 类和对象

  1. 类class和对象object区别在于class必须new生成内存才能使用,object可直接通过变量调用
  2. 类的参数可分为var变量声明和普通参数,var声明后则作为类的属性包含getset方法
  3. class和object名相同时形成伴生对象,其中类可以调用对象,对象不可调用类,对象仅作为类的辅助存在
  4. 内部类和外部类在实例化时,必须先实例化外部类,以val方式

类的参数var

class Stu(var sname:String,sex:String) {//var表示属性,不写则只是参数
  println("我是构造方法中的语句")//语句
  val xage=8//类的属性
  def this(age:Int){
    this("ghy","man")
    println("我是一个参数的构造方法")
  }
  def say=println("say...")//方法
  override def toString: String = "你叫"+sname
}
 object  ok{
   def main(args: Array[String]): Unit = {
     var x=new Stu(77)
     x.sname="吕布"
     println(x)
   }
 }

内部类和外部类=>


class myOuter(var oname:String){
  //外部类的标号
  myouter=>
  //内部类
  class myInner(var iname:String){
    println("内部类的构造方法:"+myouter.oname)
  }
}
object demo02{
  def main(args: Array[String]): Unit = {
    //实例化外部类,必须val
    val x=new myOuter("outer")
    //实例化内部类,必须val
    val y=new x.myInner("inner")
  }
}

提取器方法unapply

object RichFile{
  //unapply方法接受一个对象,然后从中提取值
  def unapply(input: String)={
    val data=input.split("/")
    if(data==null)
      None
    else
    //Some方法将接收的对象返回给参数
      Some(data(data.length-1))
  }
}
object a10{
  def main(args: Array[String]): Unit = {
    val file="/home/cay/readme.txt"
    val RichFile(x)=file//自定义参数名为x
    println(x)//x打印为Some方法拆分出的参数值
  }
}

单例模式object

//单例模式,可以用object直接写一个对象,调用时就是单例的
object Singletondemo {}
object AppTest3{
  def main(args: Array[String]): Unit = {
    var s1=Singletondemo
    var s2=Singletondemo
    //调用多次只生成一块内存
    println(s1+"\n"+s2)//地址相同
  }
}

工厂模式apply…match case …=>

abstract class Animal
object Animal{
  //工厂模式,区分不同构造器,仅提供构造方法
  def apply(stype:String): Animal = stype match {
    case "cat"=>new Cat//传入的stype值为cat则触发=>后的操作
    case "dog"=>new Dog
    case _=>new Pig//_表示else
  }
}
//自定义类继承父类
class Cat extends Animal{println("cat...")}
class Dog extends Animal{println("dog...")}
class Pig extends Animal{println("pig...")}
object a2{
  def main(args: Array[String]): Unit = {
    val x=Animal("cat")//通过apply方法无需指定方法自动调用提取器
  }
}

WordCount练习

//Source读取本地文件,split按空格拆分,返回字符串数组
val str=Source.fromFile("e:/1.txt").mkString.split("\\s")
//map中生成元组(单词,1),groupBy按每个元组的第一个元素即单词分组,返回元组的集合
var ma=str.map((_,1)).groupBy(_._1)
//分组后的元组集合的每个元素长度即该单词出现的频数,转换成List后按第二个元素即频数排序后转为降序,返回列表集合
var li2=ma.map(w=>(w._1,w._2.size)).toList.sortBy(_._2).reverse
//new PrintWriter生成写入对象,将字符串写入本地文件
var wr=new PrintWriter("e:/2.txt")
for(i<-li2)wr.write(i._1+"->"+i._2+"\n")
//关闭写入对象
wr.close()

模式匹配多种类型Any

  def main(args: Array[String]): Unit = {
    var s=match01("two")
    println(s)
  }
  def match01(x:Any)={
    //传入Any返回Any
    x match {
      case 1 =>"one"
      case _:Int=>"Int"//_:指定数据类型
      case "two"=>2
      case _:String=>"String"
    }
  }

伴生对象object …class

//类可调用其伴生对象的属性
class 伴生 {
  var xname:String="雷霆"
  def say={
    printf("say.....%d\n",伴生.xage)
    println(f"xname:$xname")
    伴生.two
  }
}
//伴生对象,不可调用类的属性
object 伴生{
  var xage:Int=8
  def two()={
    println("比利时VS日本")
  }
}
object demo{
  def main(args: Array[String]): Unit = {
    //new 则实例化类,不new则调用对象
    val x=new 伴生
    x.say
  }
}

7. 其他

捕获异常

  1. 通过try catch case捕获
    //捕获异常
    try {
      var x=1/0
    }catch {
      //case _:Exception=>println("全部错误")
      case _:ArithmeticException=>println("除数不能为0")
      case _:Exception=>println("全部错误")
    }

迭代器

  1. 通过序列方法iterator返回迭代器
    //迭代器
    val x=1 to 5
    var it=x.iterator
    while (it.hasNext){
      val v=it.next
      println(v)
    }

猜你喜欢

转载自blog.csdn.net/wxfghy/article/details/80829044
今日推荐