惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
人人都是产品经理
人人都是产品经理
H
Hacker News: Front Page
Stack Overflow Blog
Stack Overflow Blog
B
Blog
I
InfoQ
GbyAI
GbyAI
T
The Blog of Author Tim Ferriss
F
Fortinet All Blogs
Y
Y Combinator Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
月光博客
月光博客
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
F
Full Disclosure
Hacker News - Newest:
Hacker News - Newest: "LLM"
Recent Announcements
Recent Announcements
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Jina AI
Jina AI
T
Tailwind CSS Blog
S
Secure Thoughts
P
Privacy International News Feed
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 最新话题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
Cybersecurity and Infrastructure Security Agency CISA
Last Week in AI
Last Week in AI
W
WeLiveSecurity
Google Online Security Blog
Google Online Security Blog
P
Privacy & Cybersecurity Law Blog
D
DataBreaches.Net
Engineering at Meta
Engineering at Meta
Know Your Adversary
Know Your Adversary
P
Palo Alto Networks Blog
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Project Zero
Project Zero
V2EX - 技术
V2EX - 技术
H
Heimdal Security Blog
博客园 - Franky
阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Troy Hunt's Blog
V
Vulnerabilities – Threatpost
H
Help Net Security
Martin Fowler
Martin Fowler
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
G
GRAHAM CLULEY
博客园 - 【当耐特】

smallyu的博客

为什么买的加密货币一定要去中心化 RISC-V 虚拟机无法代替 EVM 虚拟机 Polkadot 的 Existential Deposit 机制错在哪里 利息,套利,交易策略,金融市场 LayerZero 从来不挑战比特币的地位 默认参数引起的以太坊节点运行错误 硬件钱包与资产安全 预测市场比币圈更赌场 为什么去中心化的跨链桥不可能实现 我对于 AI 时代的答案 不要投资任何隐私币 区块链技术世界的三大真理 以太坊 AA 钱包的致命问题是什么 基于 AI 语义执行的 MCP 区块链的设计 一个集成 Geth 和 CometBFT 的兼容层 我的加密货币定投策略(二) DeFi 基础: 理解 AMM 定价机制 Go 语言 GMP 调度器的原理是什么 Web3 项目分析计划 对 Psyche Network 项目的分析 continuation 教程: 理解 CPS 如何开发一个比特币符文(Runes)协议 比特币脚本开发教程 我从王垠的计算机科学视频班学到了什么 区块链技术面试题(2025年版) Rust 语言容易让新手困惑的一个“过度优化” Solana 智能合约开发教程 (1) 尝试开发一个最小 EVM 虚拟机 基于 ZK 的链上身份系统设计 一个 Web3 打赏系统的设计 鼓吹 Cursor 的人技术能力都差 关于 Code Review 的礼节 假如启动一个新的以太坊 PoS 网络 发行加密货币的最好方式 所有 BFT 共识的区块链都是中心化的 对 2025 年区块链行业的预测 Restaking 项目的经济难题 如何看懂任意区块链项目的技术架构 为什么不要做以太坊的二次开发 为什么不要做智能合约开发和 DeFi 开发 我的加密货币定投策略(一) PoS 类型的区块链如何处理分叉 Ethereum Casper 为什么需要 EIP-7251 区块链中的 PBFT 不需要第二次投票 开发者的思维方式 发币的核心要点 炒币投资的小 tips 为什么说 PoW 比 PoS 更加去中心化 牛市对普通人来说意味着什么 如何健康地远程工作 为什么比特币不用概率加密函数 程序员的 “服从权威” 心理 区块链技术面试题 如何区分公有链和联盟链 对 Layer 2 项目创业想法的回复 对区块链共识机制的理解 Pebbling Game 鹅卵石游戏 PDP 文件证明的局限性 不要小瞧 ChatGPT 为什么炒币不是一个好主意 一种在区块链上生成随机数的机制 为什么以太坊的私钥计算不可逆 关于以太坊的私钥碰撞 “猜均值的2/3” dApp 游戏设计 Proof of Storage/Space/Replication 的区别 Proofs of Retrievability 文件证明的含义 对 S-PDP 文件证明的示例和解释 我的加密货币交易机器人 对区块链行业的见闻 随机确认块的共识机制 VRF + BFT 共识引起交易失败的问题 为什么要重视编程思想 对 Web 3.0 的理解 GitBook 好用吗? 一种区块链节点存储扩容的方式 一种基于“自我中心主义”的共识机制 链表常见算法题及解析 基于 Multi-Linked List 的区块链设想 理解哈希函数与序列化 联盟链比公有链差在哪儿 在 Dijkstra 算法中保存路径 为什么数字货币使用区块链是政治问题 区块链:下一代数字身份认证体系的基石 网页技术能实现 3D 建模吗? 给区块链一个定义 从 Erlang 开始了解 Actor 模型 一种侧边导航栏的交互方式 Rust 的 ownership 是什么? Haskell 中的 Monad 是什么? 浅析 Libra 背后的区块链技术 对区块链的理性认识 Rust 基础语法概述 基于 Java 的爬虫框架 WebCollector Kotlin:简化版的 Scala JavaScript 有关联数组吗? 主流编程语言的异常处理机制 Go 语言基本语法 用 Scala 改写 Java 浅度实践 Python 获取海贼王更新信息 HTML5 音乐可视化
Scala 语法基础
2018-12-17 · via smallyu的博客

2018-12-17

Scala语法较复杂,参考软件的增量开发,学习一门编程语言也应先找到一种能够驾驭的表达方式,之后再逐步添枝加叶。Scala同时支持面向对象和函数式编程,是其语法复杂的原因之一。一些教程非常全面,但也因为全面,导致难以抽丝剥茧,抓住主干。

以下内容关注最简单的基础语法,希望根据这些内容,可以尝试编写面向对象风格的Scala代码。

语句

Scala允许语句结尾不加;,这一点类似JavaScript。

变量定义

val定义不可变变量(常量),var定义可变变量:

val msg1 = "Hello World"
var msg2 = "Hello Wrold"

val msg3: String = "Hello World"

定义变量时,类型声明在变量右侧,而且是可选的,可以不声明,编译器会自动推断。Scala中的基本类型包括:

Byte、Short、Int、Long、Char、String、Float、Double、Boolean

函数定义

函数即方法,下面是定义函数的例子:

def max(x: Int, y: Int): Int = {
  if (x > y) {
    return x
  } else { 
    return y
  }
}

与Java中方法定义的显著区别有三处:一是使用def关键字定义函数;二是类型声明在变量右侧,上文已提及;三是函数声明和函数体中间使用=连接。

注意函数声明的参数必须明确定义类型,编译器无法自动推断入参类型。返回类型则是可选的,除非函数使用了递归。另外,return关键字也是可选的,如果没有显式的返回语句,程序会将最后一次运算结果作为返回。

当然if后是单个语句也可以不使用大括号,因此该函数还可以这样描述:

def max2(x: Int, y: Int) = if (x > y) x else y

选择结构

上面的示例已经用到了if语句,Scala的if语句并无特殊之处,不过与其他语言相比,Scala用模式匹配的概念代替传统的switch结构:

val a = 1

a match {
  case 1 => println(1)
  case 2 => println(2)
  case _ =>
}

_通配符匹配所有值,用于捕获默认情况。匹配表达式中,备选项永远不会掉到下一个case,因此不需要break或return。(如果将_放到首句,程序不会继续向下执行)。但是要小心,如果程序没有匹配到选项,会抛出MatchError。

循环结构

while循环并不是Scala推荐的代码风格:

var i = 0
while (i < 5) {
  println(i)
  i += 1
}

似乎并没有难以理解的地方,这就是典型的while循环。与指令式语言相比,Scala没有++运算符,只能使用i += 1这样的语句。

提起while,就一定会想到for。Scala中的for循环与指令式语言有一些差异,简单的示例如下,程序会从0打印直到5(不包括5)。

for (i <- 0 until 5) {
  println(i)
}

Scala不推荐while循环,而更倾向于函数式的编程风格,用于遍历的foreach方法就是其一:

"abc".foreach(c => println(c))

程序会依次换行打印出a b c三个字符。如果函数体只有一行语句并只有一个参数,这行代码还可以更简洁:

"abc".foreach(println)

数组

Scala的数组并不在语言层面实现,可以实例化Array类来使用。相应的,数组下标使用小括号(也就是方法参数)表示:

val greet  = new Array[String](3)

greet(0) = "a"
greet(1) = "b"
greet(2) = "c"

greet.foreach(println)

实例化对象时,也可以直接传入默认参数。Array确实只是一个普通的类,下面的书写方式并没有黑魔法,只是用到了样本类。关于样本类,后文有提及。

val greet2 = Array("a", "b", "c")
greet2.foreach(println)

类使用class关键字定义,类中也包含字段和方法,即典型的面向对象。与Python不同,Scala仍然支持权限控制:

class Accumulator {
  private var sum = 0
  def add(b: Byte): Unit = {
    sum += b
    println(sum)
  }
}

单例对象

单例对象(Singleton对象)相当于Java中的静态类,使用object替代class关键字定义。单例对象由程序共享,可直接调用。单例对象可以作为程序入口,即将main方法定义在单例对象中。下面的程序从上面定义的Accumulator类中实例化出对象c,并调用其add方法,最终程序打印1:

object Run {
  def main(args: Array[String]): Unit = {
    val a = new Accumulator
    a.add(1)
  }
}

在同一源文件中,当单例对象和类同名时,称单例对象为类的伴生对象,类为单例对象的伴生类。类可以访问其伴生对象的私有属性和方法。

构造方法

Scala中构造方法的规则比Java要严格。Scala通过类参数的概念来实现构造方法:

class Accumulator(a: Int, b: Int)

如果类没有主体,大括号是可以省略的。实例化这个类时,就需要传入参数。在Java中的构造方法重载,对应Scala中的辅助构造器,它看起来像这样:

class Accumulator(a: Int, b: Int) {
  def this(c: Int) = this(c, 1)
}

这时类拥有两个构造方法:

val a1 = new Accumulator(1)
val a2 = new Accumulator(1, 2)

Scala构造器的严格之处就在于,第二个构造器只能借助第一个或超类的构造器。

继承与重写

Scala的继承与Java没有明显差异,只是方法重写必须要使用override关键字:

class A(a: Int) {
  def test = println("a")
}

class B(b: Int) extends A(b) {
  override def test = println("b")
}

特质

特质(trait)和单例对象相像,除了定义时使用的关键字不同,其余和普通的类一样,可以包含字段和方法。特质的意义在于,支持混入(Mixins),并且允许混入多个特质。这一特性经常和多重继承进行对比。

trait A {
  def aMethod = println("A")
}

trait B {
  def bMethod = println("B")
}

class C extends A with B

这样C的实例就可以调用aMethod和bMethod:

val c = new C
c.aMethod
c.bMethod

样本类

样本类的定义要在class前加case关键字,即类在定义时用case修饰。这种修饰可以让Scala编译器自动为类添加一些便捷设定:1. 实例化可以省略new关键字;2. 自动将参数作为类字段;3. 自动为类添加toString、hashCode和equals:

case class A(a: Int) {
  def aMethod = println(a)
}

object Run {
  def main(args: Array[String]): Unit = {
    val a = A(1)
    a.aMethod     // 1
    println(a)    // A(1)
    println(a.a)  // 1
  }
}

其他

与Java相比,Scala支持抽象类,但不支持接口,抽象类使用abstract定义,接口则由特质代替。Scala同样支持泛型、注解等语法。

后续

以上内容并不全面,也许并不够用。使用一种编程语言,除了掌握它的基本语法外,还要熟悉它的惯用写法,尤其像Scala这种多范式的编程语言。之后会持续修改完善此篇内容,也将继续讨论Scala的其他语言特性。