Scala(一)数据类型和使用

Scala简介

Scala 是一种基于 JVM 的多范式编程语言,这里的范式可以理解为一种编程 风格,比如面向对象编程就是一种范式。常见范式包括:面向过程、面向对象、 泛型以及函数式编程。

dos窗口下测试 类似java编译机制

创建一个文件名为.scala的文件

object Test01 {
  def main(args:Array[String]) = {
    println("Hello,World")
  }
}

在这里插入图片描述

一、Scala特点

1.1 静态类型

  1. Scala的变量声明后不允许改变类型,换句话说所有的变量和表达式在编译时就已经完全确定。这一点和Java是一样的。
  2. 可以增强IDE的类型感知能力,适大型复杂系统开发
    感知就是在使用的时候,就能够去获取它的类型
  3. 可读性好,可以声明时指定类型,且使用前必须确定类型

1.2 强类型

Scala是强类型语言,一个变量被指定了某个人数据类型,如果不经过强制转换,name它就永远是这个数据类型,也就是说不允许隐式类型转换。意味着 Scala 是类型安全的语言,这点和 Java 也相同,但 Scala 在声明变量时一般无需显示指 定类型,Scala 编译器会自动推断出类型

       Scala没有提供Java中的强制类型转换,取代方法有:
       ①、对象名.asInstanceOf[XXX]
       ②、对象名.toXXX 方法
       ③、隐式转换(implicit 关键字)

1.3 面向对象编程(OOP)

Scala 中一切值都是对象,可以说 Scala 比 Java OOP 更纯粹。比如,Java 中类 对象(包含静态字段和方法)便不是纯粹的对象,因为类是一个抽象的概念,对 象是类的实例,是一个具体的概念。所以 Scala 中去除了 static 关键字,使用一 种特殊的对象来模拟类对象(伴生对象),使得类的所有静态内容都可以放置在 它的伴生对象中声明和调用。

二、伴生对象

伴生对象

package one

// 构造函数创建:变量在前,类型在后,自动映射到类里变成属性
class Scala_Basic(name:String,age:Int){


  // 方法   变量写在类里
  def show():Unit={
    println(s"my name is $name, I'm $age")   // 格式化
  }
}

// 伴生对象(有同名类)
object Scala_Basic {
  def main(args: Array[String]): Unit = {
  // 为了把常量区分开,放在Object中,也体现了动静分离

    // 创建变量的方式
    var a = new Test("henrry",18)
    a.show()    // 调用方法
  }
}

=>  my name is henrry, I'm 18

三、Scala关键字

Java 与 Scala 关键字对比:

在这里插入图片描述

四、Scala变量和常量

val:定义常量(value)
var:定义变量(variable)
区别:val定义的参数是,不能被再次赋值,而var定义的参数可以被再次赋值。一般不严格说明时,变量和常量也统称为变量。变量是可变变量,而常量是 不可变变量。

示例代码:
var val

package one

object Review {


  def main(args: Array[String]): Unit = {

    val a = 18
    println(a)
    var b = 10
    println(b)

    println("--------")
    //这里如果写上a=10重新赋值会直接报错,执行不了
    //a=10 这里是写写不了的,直接会报错  
    println(a)
    b = 20
    println(b)
  }
}

可以看出val定义的常量a不能被改变,而var定义的变量b重新赋值后值改变了
在这里插入图片描述
变量的创建方式
在scala中,数值类型为一类类型(包括八大类型)

// 可以不指定类型,但是一定要赋值
var a = 1
var b:Int = 2

// 正确声明变量的方式
    var a = 1
    var b:Int = 2
    var c:String = "henrry"
    var g:Char = '男'
    var s:Double = 80.0
    var d:Int = _     // 没有值得时候可以给个下划线:_
	
	val e:Int = _   // 这个时候就会报错,常量必须初始化


	定义一个变量	
	var 变量名称:类型 = xxx
	一般无需显示指定类型,Scala编译器会自动推断出类型

	常量:
	val 常量名称:类型=xxx



	使用类型别名定义变量
	type 类型别名 = 类型

	type T = String
	val name:T = "Json"
var m:String = _
m: String = null
自动判断值为null,如果不给值又不给类型,无法判断

五、Scala数据类型

在这里插入图片描述

  1. 整体上分为两类:值类型(AnyVal)引用类型(AnyRef),超级父类为Any超级子类为Nothing
  2. 值类型和Java八大基本类型一致(byte、short、int、long、float、double、char、boolean),注意在Scala中所有类型首字母都大写,还有一个Unit类型,类似于Java中的void,除 了 scala.Unit 和 scala.Boolean 外其余都是数字类型。
  3. 所有的非值类型都是引用类型,,如果 Scala 运行中 Java 环境中,AnyRef 相当于 java.lang.Object。特别地,Scala 中的 String 类型等同于 java.lang.String。
  4. 值类型:直接存储值,在栈上存储其值。
  5. 引用类型:存储对其值得引用,在栈上存储地址,在堆上存储值。
  6. ==是值比较,eq(b)为地址比较
  7. AnyRef是所有引用类型的超类
  8. AnyVal是所有值类型的超类
  9. Nothing是所有值得子类
  10. Null是空引用

5.1 Unit

Unit 代表没有任何意义的值类型,他是 AnyVal 的子类型,仅有一个实例对 象“()”,叫做无用占位符,类似于 Java 中的 void 类型。
Null

  1. 类型Null只有一个对象(Java中null不是对象)
  2. 所有引用类型的子类

Nothing

  1. 所有类型子类,也是Null的子类

Unit

  1. 无意义的值类型
  2. 类似于Java中的void
  3. 在scala中有返回值(),scala中一切表达式都有值

结构图
在这里插入图片描述

一般来说用map较多
在这里插入图片描述

package two

object Test {
  def main(args: Array[String]): Unit = {

// 声明了一个map
    var map = Map("henrry" -> 18, "areiel" -> 20, "pola" -> 14)
    map.keys.foreach(println)
  }
}


=> henrry
   areiel
   pola

数组

package two

object Test {
  def main(args: Array[String]): Unit = {

    var arr = Array(11,2,33,42,14)
    // 模拟数组下标,用下标做一个数组
    var ixArr = Range.apply(0,arr.length)
    arr.foreach(x=>print(s"$x\t"))
    println()
    ixArr.foreach(x=>print(s"$x\t"))
  }
}
=>输出结果
11	2	33	42	14	
0	1	2	3	4	

Range
Range 区间类型。本质上就是一种特殊的Array
可以使用 range() 方法来生成一个区间范围内的数组。range() 方法最后一个参数为步长,默认为 1,可以参照上面的代码。

    var arr = Range.apply(1,5)
    for (elem <- arr) {
      print(elem+"\t")
    }
=>输出1	2	3	4
可以理解为1 until 5	

测试一下
    var arr = Range.apply(1,5)

    print(arr)
=>输出Range 1 until 5

六、Scala字符串插值(拼接/插值器)

Scala 为我们提供了三种字符串插值的方式,分别是 s, f 和 raw。其本质都 是定义在 StringContext 中的方法
# s 利用之后学习的隐式转换实现

IDE下测试

// $符号可以理解为引用值
val name = "henrry"
println(s"my name is $name")
=> my name is henrry

println(s"1 and 1 eq ${1+1}")
=> 1 and 1 eq 2

或者可以这么写,声明了变量类型(可写可不写)
在Scala中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。但是一定要赋初值
var x:Int = 2
println(x)
=> 2

# f 简单格式化

var name = "henrry";var age = 19;var score=88.123;var gender = '男'
println(f"name=$name%s,age=$age%d,score=$score%.2f,gender=$gender%c")
=> name=henrry,age=19,score=88.12,gender=

# raw 即所见所得,不转义

println(s"a\tb\nc\td")
println("------")
println(raw"a\tb\nc\td")
=> a	b
   c	d
   ------
   a\tb\nc\td

④、模式匹配
类似于switch case

var score = 88
var  rst = score.match {
// i就是score,是隐式参数传进来的
	case i if i>=80 =>"A"
	case i if i>=70 =>"B"
	case i if i>=60 =>"C"
	case i =>"D"     // 相当于default
println(rst)
}

=> 输出结果 A

字符串

var line:String = """"""

var s = 'Abc     // 符号变量
println(s.isInstanceOf[scala.Symbol])
=>true

DOS窗口下测试

scala> val a = 20
a: Int = 20

scala> a
res1: Int = 20

scala> print(s"a的变量为:$a")
a的变量为:20
scala> print(s"a+a的变量为:${a+a}")
a+a的变量为:40
scala> val height = 1.8
height: Double = 1.8

scala> val name = "zhangsan"
name: String = zhangsan

scala> print(f"$name%s的身高为$height%2.2f")
zhangsan的身高为1.80
scala> print(f"$name%s的身高为$height%2.3f")
zhangsan的身高为1.800
scala> print(raw"$name \n $height")
zhangsan \n 1.8
scala> val x = 10
x: Int = 10

scala> if(x>0){ print("x大于0")}
x大于0
scala> print(f"$name%s的身高为$height%.3f")
zhangsan的身高为1.800
scala> print(f"$name%s的身高为$height%5.3f")
zhangsan的身高为1.800

针对5.3f前面的5是什么意思
scala> print(f"$height%10.3f")
     1.800
scala> print(f"$height%1.3f")
1.800
指的是前面的空格数

七、函数的定义

  1. 函数的定义以def开始,然后是函数名,类似于 def main
  2. 跟着的是括号里使用逗号分隔的参数类型键值对,类似x:Int,y:Int
  3. 下面的代码表示maxInt函数带有两个参数:x和y,都是Int类型,在函数列表后,会使用"返回值类型="的形式声明函数的返回值类型,我的理解是,一切函数都是值,最后的肯定是一个值,如果需要返回值,则需要用返回类型接收确认返回值。

定义格式:

def functionName ([参数列表]) : [return type] = {
   function body
}
def maxInt(x:Int) = {
	if(x > y) x else y
}

// 调用函数
val m = maxInt(6,9)
println(m)
=> 9

函数
函数有23种,由trait定义
在这里插入图片描述

package one

object Process2 {

// 简洁的写函数
  val func = (x: Int, y: Int) => {
    x + y
    // 最后一句话是什么,返回值就是什么,没有return
  }

// 完整的去写一个函数
val fun2 = new Function2[Int, Double, Double] {   // 泛型 ,输出类型为Double型

    override def apply(v1: Int, v2: Double): Double = v1 + v2
  }


  def main(args: Array[String]): Unit = {
		  println(func(1,2))
		  println(fun2(1,2))
  }
}
=>   输出都为3

类型转换
Boolean a = obj.instanceOf[Xxx]
Xxx a = Obj.asInstanceOf[Xxx]
obj.toXxx
隐式转换(implicit Xxx)

package one

object Process2 {

 
  }

  def main(args: Array[String]): Unit = {
    var a : String = "henrry"
    println(a.isInstanceOf[String])  // isInstance:判断是不是指定类型
=>返回true

	println(a.isInstanceOf[Int])
=>返回false

// 尝试转换类型
var a : String = "henrry"
println(a.isInstanceOf[String])
if(a.asInstanceOf[Boolean]){
	println("ok")
}
//这里运行会直接报错,不给转,也因此证明了scala是强类型
  }

// 创建一个数组
    var arr:Array[Int] = Array(1,5,3,2)
    println(arr.toList)
=>  List(1, 5, 3, 2)
	
	println(arr.toString)
=>  [I@6bdf28bb

	println(arr.toSet)
=>	Set(1, 5, 3, 2)
		
// 万物皆可to,直接转换	


}

定义一个函数
一切函数都为值
可以将函数作为参数和返回值

object Process2 {
	
  val fun2 = new Function2[Int, Double, Double] {

    override def apply(v1: Int, v2: Double): Double = v1 + v2
  }


def main(args: Array[String]): Unit = {
		// 定义一个方法
		def add(x:Doubele,y:Int):Double = {
		println(s"$x + $y = ${x+y}")
			x + y	
}

	println(add(fun2(1,2)),3)  先调用fun2的方法,得到一个结果,再将这个结果作为add方法的输入最终得到一个结果
=>   输出6.0  
3.0 + 3 = 6.0
6.0

// 验证了一切函数都为值
}


}

方法和函数的区别

  1. 方法有返回值,函数不写返回值
  2. 函数归根结底就是值,可以作为参数传进方法里
    // 方法有返回值,函数不写返回值
    // 函数归根结底就是值,可以作为参数传进方法里
    val add = (x:Int,y:Int)=>{  // 如果这里写了返回值会报错
    x+y

    }

    // 方法一般这么写
    // 方法标准书写是 def 方法名(参数)[泛型]
    def m1(x:Int,y:Int):Int = {
      x+y
    }
    
println(add(1,2))   =>   3
m1(1,2)             =>   3
println(m1(add(1,2),3)):将函数作为参数传进去,其实就是传值
//  add(1,2)--> m1(3,3)


    // 函数作为参数传递
    def m2(f:(Int,Int)=>Int,x:Int,y:Int):Int = f(x,y)

    println(m2(add, 1, 2))
  }

    // 函数作为返回值
  def m3():(Int,Int)=>Int=(x:Int,y:Int)=>x+y

  println(m3()(2,3))

andThen && compose

  // 写两个简单函数
  val f1 = (x: Int) => x + 3
  val f2 = (x: Int) => x * 3
  val f3 = (x: Int) => x-1

// 柯里化 :一个函数的输出作为下一个函数的输入
  def f = f1 andThen f2 andThen f3

  println(f(2))   // 这两个函数先后调用   f1函数的输出是f2函数的输入
=>输出14

  def f3 = f1 compose f2
  println(f3(2))    // 先执行f2再执行f1
  =>输出9        2*3+3



先后执行顺序的不同


八、程序控制

8.1 条件控制(重点if)

var b : Int = 5
var a = if(b>5) "a" else 2.0
=> 2.0

val x = 9
val y = if(x==10) x+1 
println(y   )
=> ()
如果说if后面没有else,则默认else部分的值是Unit,返回()

8.2 块表达式{}

也是一个结果,{}中最后一行的结构就是快表达式的结果

var a = {
	 var a =6;var b = 5;
      a*b    // 把想要的值写在最后一行就行,包括函数,包括方法
    }
    println(a)
    =>  30

#赋值语句的结果为Unit
var x = 10
var y = {
	x = x * 2
	//x*2
}
println()
=> ()
// 创建代码块时即创建了一个作用域,在代码块内可以访问代码块外的实体 (变量、函数、类),反之不成立。因为最后一个是表达式,不是值,输出为Unit,但是当我加上了x*2后,一切都是值,这个时候就可以打印值40

九、for循环

9.1 单循环

循环

for (i <- 表达式) { 
	statements 
}

#Range  min  to/until  max  by step
to 包含max,until不包含max
// 循环
// 像数组但不是数组,如果要转为数组,直接在后面.toArray
    var arr = Range.apply(1,10,2)   // 2代表的是步幅为2
    for (elem <- arr) {
      println(elem)
    }

// 更为简洁的一种方式
    for (elem <- 1 until 10 by 2) { // 直接 1 to 10 by 2.for 就k可以出来
      print(elem)
    }
=>输出结果为 1 3 5 7 9
  1. 首先,变量 i 不需要声明。严格来说是 i 前面不允许有 val 或 var。i 可以是作 用域内的现有变量。
  2. 其次“<-”是关键字,非操作符,类似 Java 中的“:”。
  3. 最后表达式可以是数组、元组、集合。在 Scala 中 Range 是常用的集合类型, 表示范围区间。

Range min to/until max by step :指的是从最小值到最大值,步长为多少
to与until的区别:to是到多少,可以取到最大值,until是直到多少,取不到最大值
to:[]
until:[)

案例:
对这个值更进一步处理

// if和前一个语句之间可加分号,可不加分号,验证都没有错误
    for (i <- 0 to 10 by 2 if i % 3 == 0) {
      println(i)
    }
    // 首先从0  2 4 6 8 10中选择,可以理解为这是第一个函数的值,然后作为下一个函数的输入,筛选符合取模3等于0的数,最后筛选出 0 6 
    => 0  6

for (i <- 0 to 10 by 2 if i % 3 == 0 if i > 5) {
      println(i)
    }
=> 6
// 首先根据上面的代码可以知道,筛选出0,6 再作为最后一个函数的入口参数,最后可以得到6

  for (i <- 1 to 20 if i % 2 == 0; j <- 1 to i if j % 3 == 0) {
      println(s"$i\t$j")
    }
=>4	3   部分结果
  6	3
  6	6
  8	3

 for (elem <- 1 to 100;if elem%7==0;if elem%3==0) {  // ;两个条件都要满足
          println(elem)
        }
=> 21  42   63   84

9.2 二重循环

for (i <- 表达式1;j <- 表达式2;....){
	statements
}


案例:
  
// 小九九
    for (i <- 1 until 10;j<-1 to i) {
      print(s"$j * $i = ${j * i}\t")
      if (j==i){
        println()
=>输出结果
1 * 1 = 1	
1 * 2 = 2	2 * 2 = 4	
1 * 3 = 3	2 * 3 = 6	3 * 3 = 9	
1 * 4 = 4	2 * 4 = 8	3 * 4 = 12	4 * 4 = 16	
1 * 5 = 5	2 * 5 = 10	3 * 5 = 15	4 * 5 = 20	5 * 5 = 25	
1 * 6 = 6	2 * 6 = 12	3 * 6 = 18	4 * 6 = 24	5 * 6 = 30	6 * 6 = 36	
1 * 7 = 7	2 * 7 = 14	3 * 7 = 21	4 * 7 = 28	5 * 7 = 35	6 * 7 = 42	7 * 7 = 49	
1 * 8 = 8	2 * 8 = 16	3 * 8 = 24	4 * 8 = 32	5 * 8 = 40	6 * 8 = 48	7 * 8 = 56	8 * 8 = 64	
1 * 9 = 9	2 * 9 = 18	3 * 9 = 27	4 * 9 = 36	5 * 9 = 45	6 * 9 = 54	7 * 9 = 63	8 * 9 = 72	9 * 9 = 81	


#注意:如果()中有多个表达式,可以使用{}代替,换行写多条语句
    for {i <- 1 to 20 if i % 2 == 0
         j<-1 to 20 if j%3==0}{
      println(s"$i\t$j")
    }for循环所有的结果保存到一个集合中,也称for推导式
#推导式:yield循环的结果输出生成集合Vector
var r = for (i <- 1 to 15 if i % 3 == 0 || i % 7 == 0)  yield  i
    r.foreach(println)
    => 3679121415
yield的作用:把i一个一个取出来放到r中
println执行的是r中的元素

print(r)
=>   Vector(3, 6, 7, 9, 12, 14, 15)


如果这么写
r.foreach(x=>println(x+2))   // x就相当于形参,所有值都加2
5
8
9
11
14
16
17

十、循环跳转语句

scala中没有break和continue,需要手动导包

    //scala中没有break,continue  需要手动导包
      import scala.util.control.Breaks._   // ._相当于.*
        breakable {
          for (elem <- 1 to 100) {
              println(elem)
            if (elem%17==0){
              break()
            }
          }
        }


十一、数据结构

在 Scala 中,对象一般都有两种方式创建,一种使用类创建,一种使用其对 应的伴生对象创建,区别在于是否使用 new 关键字。本章暂不涉及 OOP 的内容, 了解伴生对象创建的方式即可。
Scala数据结构是非常重要的知识点,并且Scala中的数据结构远比Java丰富、 复杂。但是基本原理都是相同的,比如说数组、栈、队列、链表、树、散列表。 这里主要关注线性结构,包括 Array、Seq、List、Map 及 Set 等。
对 比 Java , Scala 中 的 数 据 结 构 都 强 调 了 是 可 变 还 是 不 可 变 , 即 mutable/immutable,默认情况下,Scala 会为用户选择不可变的数据结构。两者 的差别在于:
不可变:初始化后内容不再发生变化。
可变:初始化后内容可以发生变化。

#动态内容
Class A… (变量和方法)
var a:A = new A();

#静态内容
object A… (常量)

十二 、数组

线性结构 Array、Seq、List、Map、Set
scala中有mutable和immutable两种类型,而java中的结构容量都是可变的
内容可变

数组(容量不可变)
1、创建数组的标准方式

    var arr: Array[Int] = new Array[Int](5)  // 定义数组length=5
    for (i <- 0 until arr.length) {
      arr(i) = Random.nextInt(100)      // 随机数100以内
    }

    =>遍历所有值:  arr.foreach(println)
    =>遍历某一个值: println(arr(2))


可以发现,5加到了最后,原来的数组没有变,返回了一个新数组
    var a2 = arr:+5
    a2.foreach(println)
=> 输出
71
90
40
69
32
5

   var a3 = 7+:arr
    a3.foreach(println)

在这里插入图片描述
2、维度

// 二维
    var arr = Array.ofDim[Int](2, 3)
    for (i <- 9 until arr.length; j <- 0 until arr(i).length){
        arr(i)(j) = Random.nextInt(100)
    }
    arr.foreach(x => {
      x.foreach(x => print(s"$x\t"))
      println()
    })
 =>输出结果
50	71	35	
83	2	2	
    

3、可变数组
需要导包

    import scala.collection.mutable.ArrayBuffer
    var buffer = new ArrayBuffer[Int]
    println(s"size = ${buffer.size}")

    for (i <- 1 to 10) {
     // buffer.append(Random.nextInt(100)) 可以写成
      buffer+=Random.nextInt(100)
    }
    println(s"size = ${buffer.size}")
    buffer.foreach(println)

    /**
      * append是往后加
      * prepend是往前加
      */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值