Scala语言学习一——基础语法

什么是 Scala

Scala 是一种多范式的编程语言, 其设计的初衷是要集成面向对象编程和函数式编程的各种
特 性 。 Scala 运 行 于 Java 平 台 (Java 虚 拟 机 ) , 并 兼 容 现 有 的 Java 程 序 。

为什么要学 Scala

  1. 优雅: 这是框架设计师第一个要考虑的问题, 框架的用户是应用开 雅直接影响用户体验。

  2. 速度快: Scala 语言表达能力强, 一行代码抵得上 Java 多行, 开发速
    译的, 所以和 JRuby,Groovy 比起来速度会快很多。

  3. 能融合到 Hadoop 生态圈: Hadoop 现在是大数据事实标准, Spark
    而是要完善 Hadoop 生态。 JVM 语言大部分可能会想到 Java, 但 Java
    者想实现一个优雅的 API 太费劲。

Scala 特性

面向对象特性

Scala是一种纯面向对象的语言,每个值都是对象。对象的数据类型以及行为由类和特质描述。

类抽象机制的扩展有两种途径:一种途径是子类继承,另一种途径是灵活的混入机制。这两种途径能避免多重继承的种种问题。

函数式编程

Scala也是一种函数式语言,其函数也能当成值来使用。Scala提供了轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化。Scala的case class及其内置的模式匹配相当于函数式编程语言中常用的代数类型。

更进一步,程序员可以利用Scala的模式匹配,编写类似正则表达式的代码处理XML数据。

静态类型

Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。类型系统具体支持以下特性:

  • 泛型类
  • 协变和逆变
  • 标注
  • 类型参数的上下限约束
  • 把类别和抽象类型作为对象成员
  • 复合类型
  • 引用自己时显式指定类型
  • 视图
  • 多态方法
扩展性

Scala的设计秉承一项事实,即在实践中,某个领域特定的应用程序开发往往需要特定于该领域的语言扩展。Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构:
任何方法可用作前缀或后缀操作符
可以根据预期类型自动构造闭包。

并发性

Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息。Actor可以复用线程,因此可以在程序中可以使用数百万个Actor,而线程只能创建数千个。在2.10之后的版本中,使用Akka作为其默认Actor实现。

Scala 基础语法

如果你之前是一名 Java 程序员,并了解 Java 语言的基础知识,那么你能很快学会 Scala 的基础语法。

Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的。

我们可以认为 Scala 程序是对象的集合,通过调用彼此的方法来实现消息传递。接下来我们来理解下,类,对象,方法,实例变量的概念:

  • 对象 - 对象有属性和行为。例如:一只狗的状属性有:颜色,名字,行为有:叫、跑、吃等。对象是一个类的实例。
  • 类 - 类是对象的抽象,而对象是类的具体实例。
  • 方法 - 方法描述的基本的行为,一个类可以包含多个方法。
  • 字段 - 每个对象都有它唯一的实例变量集合,即字段。对象的属性通过给字段赋值来创建。

基本语法

Scala 基本语法需要注意以下几点:

  • 区分大小写 - Scala是大小写敏感的,这意味着标识Hello 和 hello在Scala中会有不同的含义。

  • 类名 - 对于所有的类名的第一个字母要大写。
    如果需要使用几个单词来构成一个类的名称,每个单词的第一个字母要大写。
    示例:class MyFirstScalaClass

  • 方法名称 - 所有的方法名称的第一个字母用小写。
    如果若干单词被用于构成方法的名称,则每个单词的第一个字母应大写。
    示例:def myMethodName()

  • 程序文件名 - 程序文件的名称应该与对象名称完全匹配(新版本不需要了,但建议保留这种习惯)。

  • 保存文件时,应该保存它使用的对象名称(记住Scala是区分大小写),并追加".scala"为文件扩展名。 (如果文件名和对象名称不匹配,程序将无法编译)。

    示例: 假设"HelloWorld"是对象的名称。那么该文件应保存为’HelloWorld.scala"

  • def main(args: Array[String]) - Scala程序从main()方法开始处理,这是每一个Scala程序的强制程序入口部分。

Scala 注释

Scala 类似 Java 支持单行和多行注释。多行注释可以嵌套,但必须正确嵌套,一个注释开始符号对应一个结束符号。注释在 Scala 编译中会被忽略,实例如下:

object HelloWorld {
   /* 这是一个 Scala 程序
    * 这是一行注释
    * 这里演示了多行注释
    */
   def main(args: Array[String]) {
      // 输出 Hello World
      // 这是一个单行注释
      println("Hello, world!") 
   }
}

数据类型

Scala 和 Java 一样, 有 7 种数值类型 Byte、 Char、 Short、 Int、 Long、 Float 和 Double(无包装类型) 和 Boolean、 Unit 类型.
注意:Unit 表示无值, 和其他语言中 void 等同。 用作不返回任何结果的方法的结果类型。 Unit只有一个实例值, 写成()在这里插入图片描述以下为陌生的数据类型解释

Unit表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
Nullnull 或空引用
NothingNothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。
AnyAny是所有其他类的超类
AnyRefAnyRef类是Scala里所有引用类(reference class)的基类

变量的定义

  • 定义变量使用 var 或者 val 关键字
  • val修饰的变量不可以再改变,相当于java中final修饰的变量var可以改变

语法: var|val 变量名称 (: 数据类型) = 变量值

object 变量定义 extends App {


// 使用 val 修饰的变量, 值不能为修改, 相当于 java 中 final 修饰的变量
val name = "小牛人"
// 使用 var 修饰的变量, 值可以修改
var age = 18

}

注:该类实现App特质(类似接口),然后就可以不用写mian方法也可以运行
变量类型引用

在 Scala 中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。

所以,如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值,否则将会报错。

var myVar = 10;
val myVal = "Hello, Scala!";

以上实例中,myVar 会被推断为 Int 类型,myVal 会被推断为 String 类型。

Scala 多个变量声明

Scala 支持多个变量的声明:

val xmax, ymax = 100  // xmax, ymax都声明为100

字符串的格式化输出

普通输出
val name="小牛学堂"
var age=11
val
println("name ="+name,",age="+age)使用逗号隔开  

println 的ln 表示换行输出

f插值器

文字’f’插值器允许创建一个格式化的字符串, 类似于 C 语言中的 printf。
在使用’f’插值器时, 所有变量引用都应该是 printf 样式格式说明符, 如%d, %i, %f 等。

// 这里$name%s 打印 String 变量 James 和$height%2.2f 打印浮点值 1.90。
println(f"$name%s 学费 $pirce%1.2f, 网址是$url") // 该行输出有换行
printf("%s 学费 %1.2f, 网址是%s", name, pirce, url) // 该行输出没有换行
s插值器(常用)

's’允许在处理字符串时直接使用变量。
在 println 语句中将 String 变量($name)附加到普通字符串中。,

println(s"name=$name, pirce=$pirce, url=$url")

字符串插入器还可以处理任意表达式。
使用’s’字符串插入器处理具有任意表达式( 1 + 1 ) 的 字 符 串 ( 1 + 1 ) 的 以 下 代 码 片 段 。 任 何 表 达 式 都 可 以 嵌 入 到 {1 + 1})的字符串(1 + 1)的以下代码片段。 任何表达式都可以嵌入到 1+1)(1+1){}中。

println(s"1 + 1 = ${1 + 1}") // output: 1 + 1 = 2
}
val stu =new Student("taotao",18)

println(s"${stu.name}")

格式符说明:
%d整型输出,%ld长整型输出,
%o以八进制数形式输出整数,
%x以十六进制数形式输出整数,或输出字符串的地址。
%u以十进制数输出unsigned型数据(无符号数)。注意:%d与%u有无符号的数值范围,也就是极限的值,不然数值打印出来会有误。
%c用来输出一个字符,
%s用来输出一个字符串,
%f用来输出实数,以小数形式输出,默认情况下保留小数点6位。
%.100f用来输出实数,保留小数点100位。

%e以指数形式输出实数,
%g根据大小自动选f格式或e格式,且不输出无意义的零。
$f Float $4.2f 总位数保留四位,小数保留两位 四舍五入

条件表达式

if 语句

if 语句有布尔表达式及之后的语句块组成。

语法

if 语句的语法格式如下:

if(布尔表达式)
{
   // 如果布尔表达式为 true 则执行该语句块
}

如果布尔表达式为 true 则执行大括号内的语句块,否则跳过大括号内的语句块,执行大括号之后的语句块。

实例
object Test {
   def main(args: Array[String]) {
      var x = 10;

      if( x < 20 ){
         println("x < 20");

      }
   }
}
if…else 语句

if 语句后可以紧跟 else 语句,else 内的语句块可以在布尔表达式为 false 的时候执行。

语法

if…else 的语法格式如下:

if(布尔表达式){
   // 如果布尔表达式为 true 则执行该语句块
}else{
   // 如果布尔表达式为 false 则执行该语句块
}
实例
object Test {
   def main(args: Array[String]) {
      var x = 30;

      if( x < 20 ){
         println("x 小于 20");
      }else{
         println("x 大于 20");
      }
   }
}
if…else if…else 语句

if 语句后可以紧跟 else if…else 语句,在多个条件判断语句的情况下很有用。

语法

if…else if…else 语法格式如下:

if(布尔表达式 1){
   // 如果布尔表达式 1 为 true 则执行该语句块
}else if(布尔表达式 2){
   // 如果布尔表达式 2 为 true 则执行该语句块
}else if(布尔表达式 3){
   // 如果布尔表达式 3 为 true 则执行该语句块
}else {
   // 如果以上条件都为 false 执行该语句块
}

实例

object Test {
   def main(args: Array[String]) {
      var x = 30;

      if( x == 10 ){
         println("X 的值为 10");
      }else if( x == 20 ){
         println("X 的值为 20");
      }else if( x == 30 ){
         println("X 的值为 30");
      }else{
         println("无法判断 X 的值");
      }
   }
}
常用简写案例
val r= if(i<8) i
//如果没满足,就返回unit,空值

val r1:Any =if(i<8)i else "xxoo"
//两种情况可返回不同类型
//用int String的共同的父类的父类 Any
//也可以不写Any

scala循环

Scala while 循环

语法

Scala 语言中 while 循环的语法:

while(condition)
{
   statement(s);
}

在这里,statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。

condition 可以是任意的表达式,当为任意非零值时都为 true。当条件为 true 时执行循环。 当条件为 false 时,退出循环,程序流将继续执行紧接着循环的下一条语句。

实例

object Test {
   def main(args: Array[String]) {
      // 局部变量
      var a = 10;

      // while 循环执行
      while( a < 20 ){
         println( "Value of a: " + a );
         a = a + 1;
      }
   }

}

Scala for 循环

(1). i to j for 循环
语法

Scala 语言中 for 循环的语法:

for( var x <- Range ){
   statement(s);
}

以上语法中,Range 可以是一个数字区间表示 i to j ,或者 i until j,还可以是数组或集合。左箭头 <- 用于为变量 x 赋值。

实例

以下是一个使用了 i to j 语法(包含 j)的实例:
通过角标获取数组中的元素
定义一个 0 到 10的角标范围(左闭右闭)

object Test {
   def main(args: Array[String]) {
      var a = 0;
      // for 循环
      for( a <- 1 to 10){
         println( "Value of a: " + a );
      }
   }
}

以下是一个使用了 i until j 语法(不包含 j)的实例(左闭右开):

object Test {
   def main(args: Array[String]) {
      var a = 0;
      // for 循环
      for( a <- 1 until 10){
         println( "Value of a: " + a );
      }
   }
}
(2)for 循环集合

for 循环集合的语法如下:

for( var x <- List ){
   statement(s);
}

以上语法中, List 变量是一个集合,for 循环会迭代所有集合的元素。
实例

以下实例将循环数字集合。我们使用 List() 来创建集合。再以后章节我们会详细介绍集合。

object Test {
   def main(args: Array[String]) {
      var a = 0;
      val numList = List(1,2,3,4,5,6);

      // for 循环
      for( a <- numList ){
         println( "Value of a: " + a );
      }
   }
}
(3)for 循环过滤

Scala 可以使用一个或多个 if 语句来过滤一些元素。

以下是在 for 循环中使用过滤器的语法。

for( var x <- List
      if condition1; if condition2...
   ){
   statement(s);

你可以使用分号(;)来为表达式添加一个或多个的过滤条件。
实例

以下是 for 循环中过滤的实例:

object Test {
   def main(args: Array[String]) {
      var a = 0;
      val numList = List(1,2,3,4,5,6,7,8,9,10);

      // for 循环
      for( a <- numList
           if a != 3; if a < 8 ){
         println( "Value of a: " + a );
      }
   }
}
(4)for 使用 yield

你可以将 for 循环的返回值作为一个变量存储。语法格式如下:

var retVal = for{ var x <- List
     if condition1; if condition2...
}yield x

注意大括号中用于保存变量和条件,retVal 是变量, 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。

实例

以下实例演示了 for 循环中使用 yield:

object Test {
   def main(args: Array[String]) {
      var a = 0;
      val numList = List(1,2,3,4,5,6,7,8,9,10);

      // for 循环
      var retVal = for{ a <- numList 
                        if a != 3; if a < 8
                      }yield a

      // 输出返回值
      for( a <- retVal){
         println( "Value of a: " + a );
      }
   }
}

运算符/运算符重载

Scala 中的+ - * / %等操作符的作用与 Java 一样, 位操作符 & | ^ >> <<也一样。 只是有
一点特别的: 这些操作符实际上是方法。 例如:
a + b
是如下方法调用的简写:
a.+(b)
a 方法 b 可以写成 a.方法(b)

Scala 方法与函数

Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。

Scala 中的方法跟 Java 的类似,方法是组成类的一部分。

Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。

Scala 中使用 val 语句可以定义函数,def 语句定义方法。

class Test{
  def m(x: Int) = x + 3
  val f = (x: Int) => x + 3
}
方法定义

方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。

方法的返回值类型可以不写, 编译器可以自动推断出来

Scala 方法定义格式如下:

def functionName ([参数列表]) : [return type] = {
   function body
   return [expr]
}

如果你不写等于号和方法主体,那么方法会被隐式声明为抽象(abstract),包含它的类型于是也是一个抽象类型。
在这里插入图片描述

以上代码中 return type 可以是任意合法的 Scala 数据类型。参数列表中的参数可以使用逗号分隔。

以下方法的功能是将两个传入的参数相加并求和:

object add{
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b

      return sum
   }
}

简写

def addInt( a:Int, b:Int ) : Int = a + b


函数

函数的定义
方法的定义及调用
定义方法的格式为:

val functionName= (list of parameters) =>  {函数体}
实例:

在这里插入图3333333调用: f1(2) , 其中 f1 为函数的引用, 也可以叫做函数名. function1 表示一个参数的函数.

方法可转换为函数
def m( a:Int, b:Int ) : Int = a + b
val fm=m_
方法和函数的区别

1、函数可作为一个参数传入到方法中,而方法不行。
在这里插入图片描述
2、函数必须要有参数列表,而方法可以没有参数列表

传值调用与传名调用

Scala的解释器在解析函数参数(function arguments)时有两种方式:

  • 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;

  • 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部

区别:在进入函数内部前,传值调用方式就已经将参数表达式的值计算完毕,而传名调用是在函数内部进行参数表达式的值计算的。(传入函数前,是否计算完成)

这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值。

实例1:


def huaQian(): Int={
money-5
}

def shuQian()={
huaQian  //调用花钱方法
println(money)
}
  //该方法中的参数是传入一个函数,函数返回类型是Int
    def printByName(x: => Int) = {
        for(b<- 0 to 3) {
            println(s"每次都算算还剩: ${x}元")
        }
    }           
  //该方法中的参数是传入一个Int值
    def printByValue(x: Int) = {
        for (a<- 0 until  3) {
            println(s"测试: ${x}元")
        }
    }



    def main(args: Array[String]): Unit = {
        // 传名(函数)调用
        // 将shuQian方法名称传递到方法的内部执行
        printByName(shuQian)

        // 传值调用
        //printByValue 参数为一个具体的数值
        // 1. 计算shuQian的返回值 = 45
        // 2. 将45作为参数传入printByValue
        // printByValue(shuQian)
    }

实例2:


  // add方法拥有2个Int类型的参数, 返回值为2个Int的和
    def add(a: Int, b: Int) = {
        a + b
    }


    // add2方法拥有3个参数,第一个参数是一个函数, 第二个第三个为Int类型的参数
    // 第一个参数:
    //     是拥有2个Int类型的参数,返回值为Int类型的函数
    def add2(f:(Int, Int) => Int, a: Int, b: Int) = {
        f(a, b) // f(1, 2) => 1 + 2
    }




    def add3(a:Int => Int, b: Int) = {
        a(b) + b // x * 10 + 6
    }
-----------------------------------------------------------

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

  add(fxx(2, 6), 8)          //     传值调用
  add3(f1, 6)               //  传名调用
  add2(fxx, 1, 2)            //  传名调用

    }

}

可变参数函数

// 定义一个可变参数的方法
def methodManyParams(a: String*) = {
for (p <- a) {
println(p)
}
}/
/ 调用
methodManyParams("中华", "人民", "共和国")

默认参数值函数

// 带默认的参数列表
def add(a: Int = 1, b: Int = 7): Int = {
println(s"a + b = ${a + b}" )
a + b
}/
/ 调用
add(2) // 带有默认值 a 的参数, 调用时可以不传
add(b=9, a=2) // 调用时, 可以指定具体的参数值
add(b=18) // 调用如果执行修改某一个具体的参数值的话, 可以指定参数名称

部分参数应用函数

只用部分参数,并不是用所有参数

def m(a:int,b:Int):int={a+b}
val partM= m(1,_:Int) // b参数先不填充
partM(13)

简写
val partM=m(3,_:Int)

Scala 数组

Scala 语言中提供的数组是用来存储固定大小的同类型元素,数组对于每一门编辑应语言来说都是重要的数据结构之一。

声明数组变量并不是声明 number0、number1、…、number99 一个个单独的变量,而是声明一个就像 numbers 这样的变量,然后使用 numbers[0]、numbers[1]、…、numbers[99] 来表示一个个单独的变量。数组中某个指定的元素是通过索引来访问的。

数组的第一个元素索引为0,最后一个元素的索引为元素总数减1。

声明数组

以下是 Scala 数组声明的语法格式:

var z = new Array[String](3)

以上语法中,z 声明一个字符串类型的数组,数组长度为 3 ,可存储 3 个元素。我们可以为每个元素设置值,并通过索引来访问每个元素,如下所示:

z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google"

最后一个元素的索引使用了表达式 4/2 作为索引,类似于 z(2) = “Google”。

我们也可以使用以下方式来定义一个数组:

var z = Array("Runoob", "Baidu", "Google")
//直接填充数据的数据 ,也可以不加Int

处理数组

数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本的 for 循环。

以下实例演示了数组的创建,初始化等处理过程:

object Test {
   def main(args: Array[String]) {
      var myList = Array(1.9, 2.9, 3.4, 3.5)
      
      // 输出所有数组元素
      for ( x <- myList ) {
         println( x )
      }

      // 计算数组所有元素的总和
      var total = 0.0;
      for ( i <- 0 to (myList.length - 1)) {
         total += myList(i);
      }
      println("总和为 " + total);

      // 查找数组中的最大元素
      var max = myList(0);
      for ( i <- 1 to (myList.length - 1) ) {
         if (myList(i) > max) max = myList(i);
      }
      println("最大值为 " + max);
    
   }
}

Scala 数组方法

map方法

把数组里的所有数组做相同映射

arr.map((x: Int)=>x*10)    //把数组里的所有数组做相同映射,乘10
val fx =(x:Int)=>x*10
arr. map(fx)

//arr本身没有变化,但是返回一个新的数组

简写arr.map(x=>x*10)
arr.map(_*10)
flatten操作

扁平化操作
返回一个折叠成一维的数组。

val arr1: Array[String] = Array("hello hello tom", "hello jerry")

arr.map(_.split(""))   //先用map切词
 // Array(Array("hello","hello","tom"), Array("hello", "jerry"))

arr.map(_.split("")).flatten
   // Array("hello","hello","tom", "hello", "jerry")   //扁平化操作

arr.flatMap(_.split(" "))   //先map再flatten操作,可直接用flatMap()

foreach方法

循环遍历,对每个元素进行操作

arr.flatMap(_.split(" ")) .foreach(x=>println(x))
简写
arr.flatMap(_.split(" ")) .foreach(println)  //对arr中每个元素输出打印

WordCount案例scala实现1

数据: Array(“hello”,“hello”,“tom”, “hello”, “jerry”)
语言:scala实现
快捷键 :Ctrl+P 提示参数
Alt+T 补全参数声明

代码:

WordCount 
object WordCount {

    def main(args: Array[String]): Unit = {
    //准备数据
        val words: Array[String] = Array("hello tom hello jim", "hello hatano hello 菲菲")

   // 1.操作:words 数组中的每个元素根据空格进行切分
        val wordSplit: Array[Array[String]] = words.map((x: String) => x.split(" "))
   //得结果:Array(Array(hello,tom,hello,jim), Array(hello,hatano,hello,菲菲))


// 2.操作:将数组中的Array扁平化
        val fltWords: Array[String] = wordSplit.flatten
// 结果:Array(hello,tom,hello,jim, hello,hatano,hello,菲菲)


    ///3.操作:按单词进行分组,得到map,key是单词,value是单词的集合
        val mapWords: Map[String, Array[String]] = fltWords.groupBy((wd: String) => wd)
      // 结果:hello -> Array(hello, hello, hello, hello)

   //4.操作:取出map的key和value的长度,返回一个元组
        val wrdResult: Map[String, Int] = mapWords.map(wdKV => (wdKV._1, wdKV._2.length))
        //结果: (hello, 4), (tom, 1)。。。。


  // 5.Map不支持排序,需要将map转换成List, 调用sortBy方法按照单词数量降序排序
        val sortResult: List[(String, Int)] = wrdResult.toList.sortBy(t => - t._2)

//遍历打印
        sortResult.foreach(t => println(t))
    }

}

一句话写完“”


arr.map(_.spliit(" ")).flatten().groupBy()(x=>x).mapValues(_.length).toList().sortBy(x=>x._2)


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值