Scala - 快速指南


Scala - 概述

Scala 是可扩展语言的缩写,是一种混合函数式编程语言。它是由马丁·奥德斯基创建的。Scala 顺利地集成了面向对象语言和函数式语言的特性。Scala 被编译为在 Java 虚拟机上运行。许多依赖 Java 开发关键业务应用程序的现有公司正在转向 Scala 来提高其开发效率、应用程序可扩展性和整体可靠性。

在这里,我们介绍了使 Scala 成为应用程序开发人员首选的几点。

Scala 是面向对象的

Scala 是一种纯粹的面向对象语言,因为每个值都是一个对象。对象的类型和Behave由类和特征描述,这将在后续章节中进行解释。

类通过子类化和灵活的基于 mixin 的组合机制来扩展,作为多重继承的干净替代。

Scala 是函数式的

Scala 也是一种函数式语言,因为每个函数都是一个值,每个值都是一个对象,因此最终每个函数都是一个对象。

Scala 提供了定义匿名函数的轻量级语法,它支持高阶函数,允许函数嵌套并支持柯里化。这些概念将在后续章节中进行解释。

Scala 是静态类型的

与其他一些静态类型语言(C、Pascal、Rust 等)不同,Scala 不希望您提供冗余的类型信息。在大多数情况下,您不必指定类型,当然也不必重复它。

Scala 运行在 JVM 上

Scala 被编译为 Java 字节代码,由 Java 虚拟机 (JVM) 执行。这意味着Scala和Java有一个共同的运行时平台。您可以轻松地从 Java 迁移到 Scala。

Scala 编译器将 Scala 代码编译为 Java 字节代码,然后可以通过“ scala ”命令执行。“ scala ”命令与java命令类似,它执行编译后的 Scala 代码。

Scala 可以执行 Java 代码

Scala 使您能够使用 Java SDK 的所有类以及您自己的自定义 Java 类或您最喜欢的 Java 开源项目。

Scala 可以进行并发和同步处理

Scala 允许您以有效的方式表达通用编程模式。它减少了行数并帮助程序员以类型安全的方式进行编码。它允许您以不可变的方式编写代码,这使得应用并发和并行(同步)变得容易。

Scala 与 Java

Scala 具有一组与 Java 完全不同的功能。其中一些是 -

  • 所有类型都是对象
  • 类型推断
  • 嵌套函数
  • 函数是对象
  • 领域特定语言 (DSL) 支持
  • 性状
  • 闭包
  • 受 Erlang 启发的并发支持

Scala Web 框架

Scala 随处可见,尤其是在企业 Web 应用程序中。您可以查看一些最流行的 Scala Web 框架 -

Scala - 环境设置

Scala 可以安装在任何 UNIX 风格或基于 Windows 的系统上。在开始在计算机上安装 Scala 之前,您的计算机上必须安装 Java 1.8 或更高版本。

请按照以下步骤安装 Scala。

第 1 步:验证您的 Java 安装

首先,您需要在系统上安装 Java 软件开发工具包 (SDK)。要验证这一点,请根据您正在使用的平台执行以下两个命令中的任意一个。

如果 Java 安装已正确完成,那么它将显示 Java 安装的当前版本和规范。下表给出了示例输出。

平台 命令 样本输出
Windows

打开命令控制台并输入 -

\>java –版本

Java版本“1.8.0_31”

Java (TM) SE 运行时

环境(版本1.8.0_31-b31)

Java Hotspot (TM) 64 位服务器

VM(内部版本 25.31-b07,混合模式)

Linux

打开命令终端并输入 -

$java –版本

Java版本“1.8.0_31”

打开JDK运行环境(rhel-2.8.10.4.el6_4-x86_64)

打开 JDK 64 位服务器 VM(内部版本 25.31-b07,混合模式)

我们假设本教程的读者在其系统上安装了 Java SDK 版本 1.8.0_31。

如果您没有 Java SDK,请从http://www.oracle.com/technetwork/java/javase/downloads/index.html下载其当前版本并安装。

第 2 步:设置 Java 环境

将环境变量 JAVA_HOME 设置为指向计算机上安装 Java 的基本目录位置。例如,

先生编号 平台及描述
1

Windows

将 JAVA_HOME 设置为 C:\ProgramFiles\java\jdk1.7.0_60

2

Linux

导出 JAVA_HOME=/usr/local/java-current

将 Java 编译器位置的完整路径附加到系统路径。

先生编号 平台及描述
1

Windows

将字符串“C:\Program Files\Java\jdk1.7.0_60\bin”附加到系统变量 PATH 的末尾。

2

Linux

导出 PATH=$PATH:$JAVA_HOME/bin/

如上所述,从命令提示符处执行命令java -version 。

第三步:安装Scala

您可以从http://www.scala-lang.org/downloads下载 Scala 。在编写本教程时,我下载了“scala-2.11.5-installer.jar”。确保您具有管理员权限才能继续。现在,在命令提示符下执行以下命令 -

平台 命令与输出 描述
Windows

\>java –jar scala-2.11.5-installer.jar\>

此命令将显示一个安装向导,它将指导您在 Windows 计算机上安装 Scala。在安装过程中,它会询问许可协议,只需接受它,然后它会询问 Scala 的安装路径。我选择默认给定路径“C:\Program Files\Scala”,您可以根据自己的方便选择合适的路径。

Linux

命令-

$java –jar scala-2.9.0.1-installer.jar

输出-

欢迎安装Scala 2.9.0.1!

主页位于 - http://Scala-lang.org/

按 1 继续,按 2 退出,按 3 重新显示

1.................................................

[开始拆箱]

[ 处理包:软件包安装(1/1) ]

[ 开箱完毕 ]

[控制台安装完成]

在安装过程中,它会询问许可协议,接受它,输入 1,它会询问 Scala 的安装路径。我输入的是/usr/local/share,你可以根据自己的方便选择合适的路径。

最后,打开一个新的命令提示符并输入Scala -version并按 Enter。您应该看到以下内容 -

平台 命令 输出
Windows

\>scala-版本

Scala 代码运行器版本 2.11.5 -- 版权所有 2002-2013,LAMP/EPFL

Linux

$scala-版本

Scala 代码运行器版本 2.9.0.1 – 版权所有 2002-2013,LAMP/EPFL

Scala - 基本语法

如果你对Java有很好的了解,那么学习Scala就会很容易。Scala 和 Java 之间最大的语法差异是“;” 行结束符是可选的。

当我们考虑 Scala 程序时,它可以被定义为通过调用彼此的方法进行通信的对象的集合。现在让我们简单地了解一下类、对象、方法和实例变量的含义。

  • 对象- 对象具有状态和Behave。对象是类的实例。示例 - 狗有状态 - 颜色、名称、品种以及Behave - 摇摆、吠叫和进食。

  • - 类可以定义为描述与类相关的Behave/状态的模板/蓝图。

  • 方法- 方法基本上是一种Behave。一个类可以包含许多方法。在方法中编写逻辑、操作数据并执行所有操作。

  • 字段- 每个对象都有其唯一的一组实例变量,称为字段。对象的状态是由分配给这些字段的值创建的。

  • 闭包-闭包是一个函数,其返回值取决于该函数外部声明的一个或多个变量的值。

  • Traits - 特征封装了方法和字段定义,然后可以通过将它们混合到类中来重用它们。特征用于通过指定受支持方法的签名来定义对象类型。

第一个 Scala 程序

我们可以通过两种模式执行Scala程序:一种是交互模式,另一种是脚本模式

互动模式

打开命令提示符并使用以下命令打开 Scala。

\>scala

如果您的系统中安装了 Scala,将显示以下输出 -

Welcome to Scala version 2.9.0.1
Type in expressions to have them evaluated.
Type :help for more information.

在 Scala 提示符右侧输入以下文本,然后按 Enter 键 -

scala> println("Hello, Scala!");

它将产生以下结果 -

Hello, Scala!

脚本模式

使用以下指令以脚本模式编写 Scala 程序。打开记事本并将以下代码添加到其中。

例子

object HelloWorld {
   /* This is my first java program.  
   * This will print 'Hello World' as the output
   */
   def main(args: Array[String]) {
      println("Hello, world!") // prints Hello World
   }
}

将文件另存为 - HelloWorld.scala

打开命令提示符窗口,进入程序文件所在目录。' scalac '命令用于编译Scala程序,它会在当前目录中生成一些类文件。其中之一称为HelloWorld.class。这是一个字节码,将使用“ scala ”命令在 Java 虚拟机 (JVM) 上运行。

使用以下命令编译并执行您的 Scala 程序。

\> scalac HelloWorld.scala
\> scala HelloWorld

输出

Hello, World!

基本语法

以下是 Scala 编程中的基本语法和编码约定。

  • 区分大小写- Scala 区分大小写,这意味着标识符Hellohello在 Scala 中具有不同的含义。

  • 类名称- 对于所有类名称,第一个字母应大写。如果使用多个单词来构成类的名称,则每个内部单词的第一个字母应大写。

    示例- 类 MyFirstScalaClass。

  • 方法名称- 所有方法名称均应以小写字母开头。如果使用多个单词来构成方法名称,则每个内部单词的第一个字母应为大写。

    示例- def myMethodName()

  • 程序文件名- 程序文件的名称应与对象名称完全匹配。保存文件时,您应该使用对象名称保存它(记住 Scala 区分大小写)并将“ .scala ”附加到名称末尾。(如果文件名和对象名不匹配,你的程序将无法编译)。

    示例- 假设“HelloWorld”是对象名称。然后该文件应保存为“HelloWorld.scala”。

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

Scala 标识符

所有 Scala 组件都需要名称。用于对象、类、变量和方法的名称称为标识符。关键字不能用作标识符,并且标识符区分大小写。Scala 支持四种类型的标识符。

字母数字标识符

字母数字标识符以字母或下划线开头,后面可以跟更多的字母、数字或下划线。“$”字符是 Scala 中的保留关键字,不应在标识符中使用。

以下是合法的字母数字标识符-

age, salary, _value,  __1_value

以下是非法标识符-

$salary, 123abc, -salary

操作符标识符

操作符标识符由一个或多个操作符字符组成。操作符是可打印的 ASCII 字符,例如 +、:、?、~ 或 #。

以下是合法的运营商标识符 -

+ ++ ::: <?> :>

Scala 编译器将在内部“破坏”运算符标识符,将其转换为嵌入 $ 字符的合法 Java 标识符。例如,标识符 :-> 在内部将表示为 $colon$minus$greater。

混合标识符

混合标识符由字母数字标识符组成,后跟下划线和运算符标识符。

以下是合法的混合标识符 -

unary_+,  myvar_=

这里,用作方法名称的 unary_+ 定义一元 + 运算符,用作方法名称的 myvar_= 定义赋值运算符(运算符重载)。

文字标识符

文字标识符是用反引号 (` . . . `) 括起来的任意字符串。

以下是合法的文字标识符 -

`x` `<clinit>` `yield`

Scala 关键字

以下列表显示了 Scala 中的保留字。这些保留字不得用作常量、变量或任何其他标识符名称。

抽象的 案件 抓住 班级
定义 别的 延伸
错误的 最终的 最后 为了
对于一些 如果 隐含的 进口
懒惰的 匹配 新的 无效的
目的 覆盖 包裹 私人的
受保护的 返回 密封 极好的
特征 尝试
真的 类型 瓦尔 瓦尔
尽管 屈服  
- = =>
<- <: <% >:
# @

Scala 中的评论

Scala 支持单行和多行注释,与 Java 非常相似。多行注释可以嵌套,但必须正确嵌套。Scala 编译器将忽略任何注释中可用的所有字符。

object HelloWorld {
   /* This is my first java program.  
    * This will print 'Hello World' as the output
    * This is an example of multi-line comments.
    */
   def main(args: Array[String]) {
      // Prints Hello World
      // This is also an example of single line comment.
      println("Hello, world!") 
   }
}

空行和空白

仅包含空格(可能带有注释)的行称为空行,Scala 完全忽略它。标记可以由空格字符和/或注释分隔。

换行符

Scala 是一种面向行的语言,其中语句可以用分号 (;) 或换行符终止。语句末尾的分号通常是可选的。如果需要,您可以键入一个,但如果该语句单独出现在一行上,则不必键入。另一方面,如果在一行上写入多个语句,则需要分号。下面的语法是多个语句的用法。

val s = "hello"; println(s)

斯卡拉包

包是命名的代码模块。例如,Lift 实用程序包是 net.liftweb.util。包声明是源文件中的第一个非注释行,如下所示 -

package com.liftcode.stuff

可以导入Scala包,以便在当前编译范围内引用它们。以下语句导入 scala.xml 包的内容 -

import scala.xml._

您可以导入单个类和对象,例如来自 scala.collection.mutable 包的 HashMap -

import scala.collection.mutable.HashMap

您可以从单个包中导入多个类或对象,例如 scala.collection.immutable 包中的 TreeMap 和 TreeSet -

import scala.collection.immutable.{TreeMap, TreeSet}

应用动态

支持动态调用的标记特征。此特征的实例 x 允许对任意方法名称 meth 和参数列表 args 进行方法调用 x.meth(args) ,以及对任意字段名称字段进行字段访问 x.field 。Scala-2.10 中引入了此功能。

如果 x 本身不支持调用(即如果类型检查失败),则根据以下规则重写它 -

foo.method("blah") ~~> foo.applyDynamic("method")("blah")
foo.method(x = "blah") ~~> foo.applyDynamicNamed("method")(("x", "blah"))
foo.method(x = 1, 2) ~~> foo.applyDynamicNamed("method")(("x", 1), ("", 2))
foo.field ~~> foo.selectDynamic("field")
foo.varia = 10 ~~> foo.updateDynamic("varia")(10)
foo.arr(10) = 13 ~~> foo.selectDynamic("arr").update(10, 13)
foo.arr(10) ~~> foo.applyDynamic("arr")(10)

Scala - 数据类型

Scala 具有与 Java 相同的数据类型,具有相同的内存占用和精度。下表给出了 Scala 中所有可用数据类型的详细信息 -

先生编号 数据类型和描述
1

字节

8 位有符号值。范围从 -128 到 127

2

短的

16 位有符号值。范围 -32768 至 32767

3

INT

32 位有符号值。范围 -2147483648 至 2147483647

4

长的

64 位有符号值。-9223372036854775808 至 9223372036854775807

5

漂浮

32 位 IEEE 754 单精度浮点数

6

双倍的

64 位 IEEE 754 双精度浮点数

7

查尔

16 位无符号 Unicode 字符。范围从 U+0000 到 U+FFFF

8

细绳

字符序列

9

布尔值

字面意义上的 true 或字面意义上的 false

10

单元

对应无值

11

无效的

空引用或空引用

12

没有什么

所有其他类型的子类型;不包含任何值

13

任何

任何类型的超类型;任何对象都是Any类型

14

任意引用

任何引用类型的超类型

上面列出的所有数据类型都是对象。没有像 Java 那样的原始类型。这意味着您可以调用 Int、Long 等类型的方法。

Scala 基本文字

Scala 对文字使用的规则简单且直观。本节介绍所有基本的 Scala 文字。

整数文字

整数字面量通常为 Int 类型,或者后跟 L 或 l 后缀时为 Long 类型。这是一些整数文字 -

0
035
21 
0xFFFFFFFF 
0777L

浮点文字

当浮点文字后跟浮点类型后缀 F 或 f 时,浮点文字的类型为 Float,否则为 Double 类型。以下是一些浮点文字 -

0.0 
1e30f 
3.14159f 
1.0e100
.1

布尔文字

布尔文字truefalse是 Boolean 类型的成员。

符号文字

符号文字 'x 是表达式scala.Symbol("x")的简写。Symbol是一个case类,其定义如下。

package scala
final case class Symbol private (name: String) {
   override def toString: String = "'" + name
}

字符文字

字符文字是用引号引起来的单个字符。该字符可以是可打印的 Unicode 字符,也可以是由转义序列描述的。以下是一些字符文字 -

'a' 
'\u0041'
'\n'
'\t'

字符串文字

字符串文字是双引号中的字符序列。这些字符要么是可打印的 Unicode 字符,要么是通过转义序列描述的。以下是一些字符串文字 -

"Hello,\nWorld!"
"This string contains a \" character."

多行字符串

多行字符串文字是用三引号 """ ... """ 括起来的字符序列。字符序列是任意的,只是它可以仅在最后包含三个或更多连续的引号字符。

字符不一定是可打印的;换行符或其他控制字符也是允许的。这是一个多行字符串文字 -

"""the present string
spans three
lines."""

空值

null 值的类型为scala.Null,因此与每个引用类型兼容。它表示一个引用值,引用一个特殊的“null”对象。

转义序列

以下转义序列可在字符和字符串文字中识别。

转义序列 统一码 描述
\b \u0008 退格键
\t \u0009 水平标签 HT
\n \u000c 换页 FF
\F \u000c 换页 FF
\r \u000d 回车 CR
\" \u0022 双引号“
\' \u0027 单引号。
\\ \u005c 反斜杠\

Unicode 介于 0 和 255 之间的字符也可以用八进制转义符表示,即反斜杠“\”后跟最多三个八进制字符的序列。以下是显示一些转义序列字符的示例 -

例子

object Test {
   def main(args: Array[String]) {
      println("Hello\tWorld\n\n" );
   }
} 

当上面的代码被编译并执行时,它会产生以下结果 -

输出

Hello   World

Scala - 变量

变量只不过是用于存储值的保留内存位置。这意味着当您创建变量时,您会在内存中保留一些空间。

根据变量的数据类型,编译器分配内存并决定可以在保留内存中存储什么内容。因此,通过为变量分配不同的数据类型,您可以在这些变量中存储整数、小数或字符。

变量声明

Scala 有不同的声明变量的语法。它们可以被定义为值,即常量或变量。这里,myVar 使用关键字 var 声明。它是一个可以改变值的变量,这称为可变变量以下是使用var关键字定义变量的语法-

句法

var myVar : String = "Foo"

这里,myVal 使用关键字 val 声明。这意味着它是一个无法更改的变量,这称为不可变变量。以下是使用 val 关键字定义变量的语法 -

句法

val myVal : String = "Foo"

变量数据类型

变量的类型在变量名之后、等号之前指定。您可以通过提及其数据类型来定义任何类型的 Scala 变量,如下所示 -

句法

val or val VariableName : DataType = [Initial Value]

如果您没有为变量分配任何初始值,则它是有效的,如下所示 -

句法

var myVar :Int;
val myVal :String;

变量类型推断

当您为变量分配初始值时,Scala 编译器可以根据分配给变量的值确定变量的类型。这称为变量类型推断。因此,您可以像这样编写这些变量声明 -

句法

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

这里,默认情况下,myVar 为 Int 类型,myVal 为 String 类型变量。

多项作业

Scala 支持多重赋值。如果代码块或方法返回一个元组(元组- 保存不同类型的对象的集合),则可以将元组分配给 val 变量。[- 我们将在后续章节中研究元组。]

句法

val (myVar1: Int, myVar2: String) = Pair(40, "Foo")

类型推断是正确的 -

句法

val (myVar1, myVar2) = Pair(40, "Foo")

示例程序

下面是一个示例程序,解释了Scala中变量声明的过程。该程序声明了四个变量 - 两个变量是使用类型声明定义的,其余两个变量没有类型声明。

例子

object Demo {
   def main(args: Array[String]) {
      var myVar :Int = 10;
      val myVal :String = "Hello Scala with datatype declaration.";
      var myVar1 = 20;
      val myVal1 = "Hello Scala new without datatype declaration.";
      
      println(myVar); println(myVal); println(myVar1); 
      println(myVal1);
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

10
Hello Scala with datatype declaration.
20
Hello Scala without datatype declaration.

变量范围

Scala 中的变量可以具有三个不同的作用域,具体取决于使用它们的位置。它们可以作为字段、方法参数和局部变量存在。以下是有关每种范围类型的详细信息。

领域

字段是属于某个对象的变量。这些字段可以从对象中的每个方法内部访问。字段也可以在对象外部访问,具体取决于声明字段时使用的访问修饰符。对象字段可以是可变类型和不可变类型,并且可以使用varval定义。

方法参数

方法参数是变量,用于在调用方法时在方法内传递值。方法参数只能从方法内部访问,但如果您从方法外部引用了对象,则可以从外部访问传入的对象。方法参数始终是不可变的,由val关键字定义。

局部变量

局部变量是在方法内部声明的变量。局部变量只能从方法内部访问,但如果从方法返回创建的对象,则它们可能会转义该方法。局部变量可以是可变类型和不可变类型,并且可以使用varval定义。

Scala - 类和对象

本章将带您了解如何在 Scala 编程中使用类和对象。类是对象的蓝图。定义类后,您可以使用关键字new从类蓝图中创建对象。通过该对象,您可以使用已定义类的所有功能。

下图以student类为例演示了类和对象,其中包含成员变量(name和roll no)和成员方法(setName()和setRollNo())。最后全部都是班级成员。类是一个蓝图,而对象在这里是真实的。在下图中,Student 是一个类,Harini、John 和 Maria 是 Student 类的对象,它们具有姓名和学号。

Scala 类和对象

基础班

以下是在 Scala 中定义基本类的简单语法。此类定义了两个变量xy以及一个方法:move,该方法不返回值。类变量被称为类,类的字段和方法被称为类方法。

类名充当可以采用多个参数的类构造函数。上面的代码定义了两个构造函数参数,xcyc;他们在整个班级中都是可见的。

句法

class Point(xc: Int, yc: Int) {
   var x: Int = xc
   var y: Int = yc

   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

正如本章前面提到的,您可以使用关键字new创建对象,然后可以访问类字段和方法,如下例所示 -

例子

import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

object Demo {
   def main(args: Array[String]) {
      val pt = new Point(10, 20);

      // Move to a new location
      pt.move(10, 10);
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

Point x location : 20
Point y location : 30

扩展一个类

您可以扩展 Scala 基类,也可以像 Java 中一样设计继承类(使用extends关键字),但有两个限制:方法重写需要override关键字,并且只有构造函数可以通过基本构造函数的参数。让我们扩展上面的类并添加一个类方法。

例子

让我们举两个类的例子:Point类(与上面的例子相同)和Location类是使用extends关键字的继承类。这样的“ extends ”子句有两个作用:它使 Location 类继承 Point 类的所有非私有成员,并使Location类型成为Point类类型的子类型。因此,这里 Point 类称为超类, Location类称为子类。扩展一个类并继承父类的所有功能称为继承,但 Scala 只允许从一个类继承。

注意- Point 类中的 move() 方法和Location 类中的 move() 方法不会覆盖 move 的相应定义,因为它们是不同的定义(例如,前者采用两个参数,而后者采用三个参数)。

尝试以下示例程序来实现继承。

import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

class Location(override val xc: Int, override val yc: Int,
   val zc :Int) extends Point(xc, yc){
   var z: Int = zc

   def move(dx: Int, dy: Int, dz: Int) {
      x = x + dx
      y = y + dy
      z = z + dz
      println ("Point x location : " + x);
      println ("Point y location : " + y);
      println ("Point z location : " + z);
   }
}

object Demo {
   def main(args: Array[String]) {
      val loc = new Location(10, 20, 15);

      // Move to a new location
      loc.move(10, 10, 5);
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

Point x location : 20
Point y location : 30
Point z location : 20

隐式类

当类在作用域内时,隐式类允许与类的主构造函数进行隐式对话。隐式类是用“implicit”关键字标记的类。Scala 2.10 中引入了此功能。

语法- 以下是隐式类的语法。这里隐式类始终位于允许所有方法定义的对象范围内,因为隐式类不能是顶级类。

句法

object <object name> {
   implicit class <class name>(<Variable>: Data type) {
      def <method>(): Unit =
   }
}

例子

让我们以一个名为IntTimes的隐式类和 times() 方法为例。这意味着 times() 包含一个循环事务,它将按照我们给出的次数执行给定的语句。假设给定的语句是“4 次 println (“Hello”)”,意味着 println (“”Hello”) 语句将执行 4 次。

以下是给定示例的程序。在此示例中使用了两个对象类(Run 和 Demo),因此我们必须将这两个类保存在不同的文件中,并使用各自的名称,如下所示。

Run.scala - 将以下程序保存在 Run.scala 中。

object Run {
   implicit class IntTimes(x: Int) {
      def times [A](f: =>A): Unit = {
         def loop(current: Int): Unit =
         
         if(current > 0){
            f
            loop(current - 1)
         }
         loop(x)
      }
   }
}

Demo.scala - 将以下程序保存在 Demo.scala 中。

import Run._

object Demo {
   def main(args: Array[String]) {
      4 times println("hello")
   }
}

以下命令用于编译和执行这两个程序。

命令

\>scalac Run.scala
\>scalac Demo.scala
\>scala Demo

输出

Hello
Hello
Hello
Hello

注意-

  • 隐式类必须在另一个类/对象/特征内定义(而不是在顶层)。

  • 隐式类在其构造函数中只能采用一个非隐式参数。

  • 隐式类不能是范围内与隐式类同名的任何方法、成员或对象。

单例对象

Scala 比 Java 更面向对象,因为在 Scala 中,我们不能有静态成员。相反,Scala 有单例对象。单例是一种只能有一个实例的类,即 Object。您可以使用关键字object而不是 class 关键字来创建单例。由于无法实例化单例对象,因此无法将参数传递给主构造函数。您已经看过所有使用单例对象并在其中调用 Scala 的 main 方法的示例。

以下是实现单例的相同示例程序。

例子

import java.io._

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
   }
}

object Demo {
   def main(args: Array[String]) {
      val point = new Point(10, 20)
      printPoint

      def printPoint{
         println ("Point x location : " + point.x);
         println ("Point y location : " + point.y);
      }
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

Point x location : 10
Point y location : 20

Scala - 访问修饰符

本章将带您了解 Scala 访问修饰符。包、类或对象的成员可以使用访问修饰符 private 和 protected 进行标记,如果我们不使用这两个关键字中的任何一个,则访问将被假定为 public。这些修饰符限制对某些代码区域的成员的访问。要使用访问修饰符,请将其关键字包含在包、类或对象的成员的定义中,我们将在下一节中看到。

私人会员

私有成员仅在包含成员定义的类或对象内部可见。

以下是解释私有成员的示例代码片段 -

例子

class Outer {
   class Inner {
      private def f() { println("f") }
      
      class InnerMost {
         f() // OK
      }
   }
   (new Inner).f() // Error: f is not accessible
}

在Scala中,访问(新的Inner)。f() 是非法的,因为 f 在 Inner 中被声明为私有,并且访问不是来自 Inner 类内部。相比之下,第一次访问类 Innermost 中的 f 是可以的,因为该访问包含在类 Inner 的主体中。Java 允许这两种访问,因为它允许外部类访问其内部类的私有成员。

受保护会员

受保护的成员只能从定义该成员的类的子类中访问。

以下是解释受保护成员的示例代码片段 -

例子

package p {
   class Super {
      protected def f() { println("f") }
   }
   
   class Sub extends Super {
      f()
   }
   
   class Other {
      (new Super).f() // Error: f is not accessible
   }
}

在 Sub 类中访问 f 是可以的,因为 f 在“Super”类中被声明为受保护的,而“Sub”类是 Super 的子类。相比之下,不允许访问“Other”类中的 f,因为“Other”类不是从“Super”类继承的。在 Java 中,仍然允许后者访问,因为“其他”类与“子”类位于同一包中。

公众会员

与私有成员和受保护成员不同,公共成员不需要指定 Public 关键字。公共成员没有显式修饰符。可以从任何地方访问此类成员。

以下是解释公共成员的示例代码片段 -

例子

class Outer {
   class Inner {
      def f() { println("f") }
      
      class InnerMost {
         f() // OK
      }
   }
   (new Inner).f() // OK because now f() is public
}

保护范围

Scala 中的访问修饰符可以通过限定符来增强。private[X] 或 protected[X] 形式的修饰符表示“最多”X 的访问是私有的或受保护的,其中 X 指定一些封闭的包、类或单例对象。

考虑以下示例 -

例子

package society {
   package professional {
      class Executive {
         private[professional] var workDetails = null
         private[society] var friends = null
         private[this] var secrets = null

         def help(another : Executive) {
            println(another.workDetails)
            println(another.secrets) //ERROR
         }
      }
   }
}

注意- 上面示例中的以下几点 -

  • 变量 workDetails 可供封闭包 professional 中的任何类访问。

  • 封闭包社会中的任何类都可以访问变量朋友。

  • 变量秘密只能在实例方法(this)内的隐式对象上访问。

Scala - 运算符

运算符是告诉编译器执行特定数学或逻辑操作的符号。Scala 拥有丰富的内置运算符,并提供以下类型的运算符 -

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 按位运算符
  • 赋值运算符

本章将一一考察算术、关系、逻辑、位、赋值等运算符。

算术运算符

Scala 语言支持以下算术运算符。例如,假设变量 A 为 10,变量 B 为 20,则 -

显示示例

操作员 描述 例子
+ 添加两个操作数 A + B 将为 30
- 从第一个操作数中减去第二个操作数 A - B 将给出 -10
* 将两个操作数相乘 A * B 将给出 200
/ 分子除以分子 B/A 将给出 2
% 模运算符求一个数除以另一个数后的余数 B % A 将给出 0

关系运算符

Scala 语言支持以下关系运算符。例如,假设变量 A 为 10,变量 B 为 20,则 -

显示示例

操作员 描述 例子
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 不正确。
!= 检查两个操作数的值是否相等,如果值不相等则条件成立。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是,则条件为真。 (A > B) 不正确。
< 检查左操作数的值是否小于右操作数的值,如果是,则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是,则条件为真。 (A >= B) 不正确。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是,则条件为真。 (A <= B) 为真。

逻辑运算符

Scala 语言支持以下逻辑运算符。例如,假设变量 A 为 1,变量 B 为 0,则 -

显示示例

操作员 描述 例子
&& 它称为逻辑与运算符。如果两个操作数都不为零,则条件为真。 (A && B) 是错误的。
|| 它称为逻辑或运算符。如果两个操作数中的任何一个不为零,则条件为真。 (A || B) 为真。
它被称为逻辑非运算符。用于反转其操作数的逻辑状态。如果条件为真,则逻辑 NOT 运算符将为假。 !(A && B) 为真。

按位运算符

位运算符作用于位并执行逐位运算。&、| 和 ^ 的真值表如下 -

p q 质与问 p| q p^q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

假设A = 60;B=13;现在以二进制格式,它们将如下 -

A = 0011 1100
B = 0000 1101
-----------------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011

Scala语言支持的按位运算符如下表所示。假设变量 A 为 60,变量 B 为 13,则 -

显示示例

操作员 描述 例子
& 如果两个操作数中都存在,则二进制 AND 运算符会将一位复制到结果中。 (A & B) 将给出 12,即 0000 1100
| 如果任一操作数中存在该位,则二元或运算符会复制该位。 (A | B) 将给出 61,即 0011 1101
^ 如果在一个操作数中设置了该位,但不是在两个操作数中都设置了该位,则二进制 XOR 运算符会复制该位。 (A ^ B) 将给出 49,即 0011 0001
二进制补码运算符是一元的,具有“翻转”位的效果。 (~A ) 将给出 -61,由于是有符号二进制数,因此为 2 的补码形式的 1100 0011。
<< 二进制左移运算符。左操作数值的位位置向左移动右操作数指定的位数。 A << 2 将给出 240,即 1111 0000
>> 二进制右移运算符。左操作数值的位位置向右移动右操作数指定的位数。 A >> 2 将得到 15,即 1111
>>> 右移补零运算符。左操作数的值向右移动右操作数指定的位数,并用零填充移位后的值。 A >>>2 将给出 15,即 0000 1111

赋值运算符

Scala 语言支持以下赋值运算符 -

显示示例

操作员 描述 例子
= 简单赋值运算符,将右侧操作数的值分配给左侧操作数 C = A + B 将 A + B 的值赋给 C
+= 添加AND赋值运算符,它将右操作数添加到左操作数并将结果分配给左操作数 C += A 等价于 C = C + A
-= 减法AND赋值运算符,它从左操作数中减去右操作数,并将结果赋给左操作数 C -= A 相当于 C = C - A
*= 乘法与赋值运算符,将右操作数与左操作数相乘,并将结果赋给左操作数 C *= A 相当于 C = C * A
/= 除法与赋值运算符,它将左操作数与右操作数相除,并将结果赋给左操作数 C /= A 相当于 C = C / A
%= 模数与赋值运算符,它使用两个操作数取模并将结果分配给左操作数 C %= A 相当于 C = C % A
<<= 左移 AND 赋值运算符 C <<= 2 与 C = C << 2 相同
>>= 右移 AND 赋值运算符 C >>= 2 与 C = C >> 2 相同
&= 按位与赋值运算符 C &= 2 与 C = C & 2 相同
^= 按位异或和赋值运算符 C ^= 2 与 C = C ^ 2 相同
|= 按位 OR 和赋值运算符 C |= 2 与 C = C | 相同 2

Scala 中的运算符优先级

运算符优先级决定表达式中术语的分组。这会影响表达式的计算方式。某些运算符的优先级高于其他运算符;例如,乘法运算符的优先级高于加法运算符 -

例如,x = 7 + 3 * 2;此处,x 被分配为 13,而不是 20,因为运算符 * 的优先级高于 +,因此它首先乘以 3*2,然后添加到 7。

看看下表。优先级最高的运算符显示在表的顶部,优先级最低的运算符显示在底部。在表达式中,将首先计算优先级较高的运算符。

类别 操作员 关联性
后缀 ()[] 左到右
一元 !〜 右到左
乘法 * / % 左到右
添加剂 + - 左到右
转移 >> >>> << 左到右
关系型 > >= < <= 左到右
平等 ==!= 左到右
按位与 & 左到右
按位异或 ^ 左到右
按位或 | 左到右
逻辑与 && 左到右
逻辑或 || 左到右
任务 = += -= *= /= %= >>= <<= &= ^= |= 右到左
逗号 , 左到右

Scala - IF ELSE 语句

本章将带您了解 Scala 编程中的条件构造语句。以下是大多数编程语言中常见的典型决策 IF...ELSE 结构的一般形式。

流程图

下面是条件语句的流程图。

Scala IF...ELSE 结构

if 语句

“if”语句由一个布尔表达式后跟一个或多个语句组成。

句法

“if”语句的语法如下。

if(Boolean_expression) {
   // Statements will execute if the Boolean expression is true
}

如果布尔表达式的计算结果为 true,则将执行“if”表达式内的代码块。如果不是,则将执行“if”表达式结束后(右花括号后)的第一组代码。

尝试以下示例程序来理解 Scala 编程语言中的条件表达式(if 表达式)。

例子

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

      if( x < 20 ){
         println("This is if statement");
      }
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

This is if statement

如果-否则语句

“if”语句后面可以跟一个可选的else语句,该语句在布尔表达式为 false 时执行。

句法

if...else 的语法是 -

if(Boolean_expression){
   //Executes when the Boolean expression is true
} else{
   //Executes when the Boolean expression is false
}

尝试以下示例程序来理解 Scala 编程语言中的条件语句(if-else 语句)。

例子

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

      if( x < 20 ){
         println("This is if statement");
      } else {
         println("This is else statement");
      }
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

This is else statement

if-else-if-else 语句

“if”语句后面可以跟一个可选的“ else if...else ”语句,这对于使用单个 if...else if 语句测试各种条件非常有用。

使用 if 、 else if 、 else 语句时,有几点需要记住。

  • 'if' 可以有 0 个或 1 个 else,并且它必须位于任何 else if 之后。

  • 一个“if”可以有零到多个 else if,并且它们必须位于 else 之前。

  • 一旦 else if 成功,剩下的 else if 或 else 都不会被测试。

句法

以下是“if...else if...else”的语法如下 -

if(Boolean_expression 1){
   //Executes when the Boolean expression 1 is true
} else if(Boolean_expression 2){
   //Executes when the Boolean expression 2 is true
} else if(Boolean_expression 3){
   //Executes when the Boolean expression 3 is true
} else {
   //Executes when the none of the above condition is true.
}

尝试以下示例程序来理解 Scala 编程语言中的条件语句(if-else-if-else 语句)。

例子

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

      if( x == 10 ){
         println("Value of X is 10");
      } else if( x == 20 ){
         println("Value of X is 20");
      } else if( x == 30 ){
         println("Value of X is 30");
      } else{
         println("This is else statement");
      }
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

Value of X is 30

嵌套 if-else 语句

嵌套if-else语句始终是合法的,这意味着您可以在另一个ifelse-if语句中使用一个ifelse-if语句。

句法

嵌套 if-else 的语法如下 -

if(Boolean_expression 1){
   //Executes when the Boolean expression 1 is true
   
   if(Boolean_expression 2){
      //Executes when the Boolean expression 2 is true
   }
}

尝试以下示例程序来理解 Scala 编程语言中的条件语句(嵌套 if 语句)。

例子

object Demo {
   def main(args: Array[String]) {
      var x = 30;
      var y = 10;
      
      if( x == 30 ){
         if( y == 10 ){
            println("X = 30 and Y = 10");
         }
      }
   }
}

将上述程序保存在Demo.scala中。以下命令用于编译和执行该程序。

命令

\>scalac Demo.scala
\>scala Demo

输出

X = 30 and Y = 10

Scala - 循环语句

本章将带您了解 Scala 编程语言中的循环控制结构。

可能存在一种情况,当您需要多次执行一段代码时。一般来说,语句是按顺序执行的:首先执行函数中的第一个语句,然后执行第二个语句,依此类推。

编程语言提供了各种控制结构,允许更复杂的执行路径。

循环语句允许我们多次执行一条语句或一组语句,以下是大多数编程语言中循环语句的一般形式 -

流程图

循环架构

Scala 编程语言提供以下类型的循环来处理循环需求。单击表中的以下链接查看其详细信息。

先生编号 循环类型和描述
1

while 循环

当给定条件为真时,重复一个语句或一组语句。它在执行循环体之前测试条件。

2

do-while 循环

与 while 语句类似,只不过它测试循环体末尾的条件。

3

for循环

多次执行一系列语句并缩写管理循环变量的代码。

循环控制语句

循环控制语句改变其正常顺序的执行。当执行离开作用域时,在该作用域中创建的所有自动对象都将被销毁。因此,Scala 不像 Java 那样支持breakcontinue语句,但从 Scala 2.8 版本开始,有一种方法可以打破循环。点击以下