百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

有趣的 Scala 语言:简洁的 Scala 语法

itomcoil 2025-02-07 17:49 31 浏览

一、Scala开发环境

搭建Scala 开发环境,一是在IntelliJ IDEA 上安装Scala 插件和安装Scala SDK,具体操作步骤可以参考Scala专栏文章。

二是通过Scala RELP(Read-Eval-Print Loop)交互式环境,该交互式环境适合代码简单调试,不太适合进行应用开发。

二、变量和函数

定义变量时没有指定变量类型。这是否意味着 Scala 是和 Python 或者 Ruby 一样的动态类型语言呢?恰恰相反,Scala 是严格意义上的静态类型语言,由于其采用了先进的类型推断(Type Inference)技术,程序员不需要在写程序时显式指定类型,编译器会根据上下文推断出类型信息。比如变量 x被赋值为 0,0 是一个整型,所以 x的类型被推断出为整型。当然,Scala 语言也允许显示指定类型,如变量 x1,y1的定义。一般情况下,我们应尽量使用 Scala 提供的类型推断系统使代码看上去更加简洁。

另一个发现是程序语句结尾没有分号,这也是 Scala 中约定俗成的编程习惯。大多数情况下分号都是可省的,如果你需要将两条语句写在同一行,则需要用分号分开它们。

函数的定义也非常简单,使用关键字 def,后跟函数名和参数列表,如果不是递归函数可以选择省略函数返回类型。Scala 还支持定义匿名函数,匿名函数由参数列表,箭头连接符和函数体组成。函数在 Scala 中属于一级对象,它可以作为参数传递给其他函数,可以作为另一个函数的返回值,或者赋给一个变量。在下面的示例代码中,定义的匿名函数被赋给变量 cube。匿名函数使用起来非常方便,比如 List对象中的一些方法需要传入一个简单的函数作为参数,我们当然可以定义一个函数,然后再传给 List对象中的方法,但使用匿名函数,程序看上去更加简洁。


// 定义函数

def square(x: Int): Int = x * x

// 如果不是递归函数,函数返回类型可省略

def sum_of_square(x: Int, y: Int) = square(x) + square(y)

sum_of_square(2, 3)


// 定义匿名函数

val cube = (x: Int) => x * x *x

cube(3)

// 使用匿名函数,返回列表中的正数

List(-2, -1, 0, 1, 2, 3).filter(x => x > 0)


让我们再来和 Java 中对应的函数定义语法比较一下。首先,函数体没有像 Java 那样放在 {}里。Scala 中的一条语句其实是一个表达式,函数的执行过程就是对函数体内的表达式的求值过程,最后一条表达式的值就是函数的返回值。如果函数体只包含一条表达式,则可以省略 {}。其次,没有显示的 return语句,最后一条表达式的值会自动返回给函数的调用者。

和 Java 不同,在 Scala 中,函数内部还可以定义其他函数。比如上面的程序中,如果用户只对 sum_of_square 函数感兴趣,则我们可以将 square 函数定义为内部函数,实现细节的隐藏。


定义内部函数:


三、流程控制语句

复杂一点的程序离不开流程控制语句,Scala 提供了用于条件判断的 if else和表示循环的 while。和 Java 中对应的条件判断语句不同,Scala 中的 if else是一个表达式,根据条件的不同返回相应分支上的值。比如下面例子中求绝对值的程序,由于 Scala 中的 if else是一个表达式,所以不用像 Java 那样显式使用 return返回相应的值。


使用 if else 表达式:

def abs(n: Int): Int = if (n > 0) n else -n


和 Java 一样,Scala 提供了用于循环的 while 语句,在下面的例子中,我们将借助 while 循环为整数列表求和。

使用 while 为列表求和:

def sum(xs: List[Int]) = {

var total = 0

var index = 0

while (index < xs.size) {

total += xs(index)

index += 1

}

total

}


上述程序是习惯了 Java 或 C++ 的程序员想到的第一方案,但仔细观察会发现有几个问题:首先,使用了 var定义变量,我们在前面说过,尽量避免使用 var。其次,这个程序太长了,第一次拿到这个程序的人需要对着程序仔细端详一会:程序首先定义了两个变量,并将其初始化为 0,然后在 index小于列表长度时执行循环,在循环体中,累加列表中的元素,并将 index加 1,最后返回最终的累加值。直到这时,这个人才意识到这个程序是对一个数列求和。


让我们换个角度,尝试用递归的方式去思考这个问题,对一个数列的求和问题可以简化为该数列的第一个元素加上由后续元素组成的数列的和,依此类推,直到后续元素组成的数列为空返回 0。具体程序如下,使用递归,原来需要 9 行实现的程序现在只需要两行,而且程序逻辑看起来更清晰,更易懂。


使用递归对数列求和:

//xs.head 返回列表里的头元素,即第一个元素

//xs.tail 返回除头元素外的剩余元素组成的列表

def sum1(xs: List[Int]): Int = if (xs.isEmpty) 0 else xs.head + sum1(xs.tail)


有没有更简便的方式呢?答案是肯定的,我们可以使用列表内置的一些方法达到同样的效果:


上述使用了规约操作。

规约操作是对容器的元素进行两两运算,将其规约为一个值。最常见的规约方式使 reduce,它接受一个二元函数 f 作为参数,首先将 f 作用在某两个元素上并返回一个值,然后再将 f 作用在上一个返回值和容器的下一个元素上,再返回一个值,依次类推,最后容器中的所有值会被规约为一个值。


list map (_.toString) reduce((x,y)=>s"f($x,$y)")

上面这行代码:先通过 map 操作将List[Int] 转化成 List[String],也就是把列表中的每个元素从 Int 类型转换成 String 类型,然后对这个字符串进行自定义规约,语句的执行结果清楚地展示了 reduce的过程。


事实上,List 已经为我们提供了 sum 方法,在实际应用中,我们应该使用该方法,而不是自己定义一个。作者只是希望通过上述例子,让大家意识到 Scala 虽然提供了用于循环的 while 语句,但大多数情况下,我们有其他更简便的方式能够达到同样的效果。



四、如何运行 Scala 程序?

在运行方式上,Scala 又一次体现出了它的灵活性。它可以被当作一种脚本语言执行,也可以像 Java 一样,作为应用程序执行。


作为脚本执行:

我们可以将 Scala 表达式写在一个文件里,比如 Hello.scala。在命令行中直接输入 scala Hello.scala就可得到程序运行结果。

Hello.scala 代码:

println("Hello Rickie!")


作为应用程序执行:

作为应用程序执行时,我们需要在一个单例对象中定义入口函数 main,经过编译后就可以执行该应用程序了。

object HelloRickie {

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

println("Hello Rickie!")

}

}


Scala 还提供了一个更简便的方式,直接继承另一个对象 App,无需定义 main方法,编译即可运行。


五、结束语

本文为大家介绍了 Scala 的基本语法,相比 Java,Scala 的语法更加简洁,比如 Scala 的类型推断可以省略程序中绝大多数的类型声明,短小精悍的匿名函数可以方便的在函数之间传递,还有各种在 Scala 社区约定俗成的习惯,比如省略的分号以及函数体只有一条表达式时的花括号,这一切都帮助程序员写出更简洁,更优雅的程序。

相关推荐

selenium(WEB自动化工具)

定义解释Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8,9,10,11),MozillaF...

开发利器丨如何使用ELK设计微服务中的日志收集方案?

【摘要】微服务各个组件的相关实践会涉及到工具,本文将会介绍微服务日常开发的一些利器,这些工具帮助我们构建更加健壮的微服务系统,并帮助排查解决微服务系统中的问题与性能瓶颈等。我们将重点介绍微服务架构中...

高并发系统设计:应对每秒数万QPS的架构策略

当面试官问及"如何应对每秒几万QPS(QueriesPerSecond)"时,大概率是想知道你对高并发系统设计的理解有多少。本文将深入探讨从基础设施到应用层面的解决方案。01、理解...

2025 年每个 JavaScript 开发者都应该了解的功能

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.Iteratorhelpers开发者...

JavaScript Array 对象

Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...

Gemini 2.5编程全球霸榜,谷歌重回AI王座,神秘模型曝光,奥特曼迎战

刚刚,Gemini2.5Pro编程登顶,6美元性价比碾压Claude3.7Sonnet。不仅如此,谷歌还暗藏着更强的编程模型Dragontail,这次是要彻底翻盘了。谷歌,彻底打了一场漂亮的翻...

动力节点最新JavaScript教程(高级篇),深入学习JavaScript

JavaScript是一种运行在浏览器中的解释型编程语言,它的解释器被称为JavaScript引擎,是浏览器的一部分,JavaScript广泛用于浏览器客户端编程,通常JavaScript脚本是通过嵌...

一文看懂Kiro,其 Spec工作流秒杀Cursor,可移植至Claude Code

当Cursor的“即兴编程”开始拖累项目质量,AWS新晋IDEKiro以Spec工作流打出“先规范后编码”的系统工程思维:需求-设计-任务三件套一次生成,文档与代码同步落地,复杂项目不...

「晚安·好梦」努力只能及格,拼命才能优秀

欢迎光临,浏览之前点击上面的音乐放松一下心情吧!喜欢的话给小编一个关注呀!Effortscanonlypass,anddesperatelycanbeexcellent.努力只能及格...

JavaScript 中 some 与 every 方法的区别是什么?

大家好,很高兴又见面了,我是姜茶的编程笔记,我们一起学习前端相关领域技术,共同进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力在JavaScript中,Array.protot...

10个高效的Python爬虫框架,你用过几个?

小型爬虫需求,requests库+bs4库就能解决;大型爬虫数据,尤其涉及异步抓取、内容管理及后续扩展等功能时,就需要用到爬虫框架了。下面介绍了10个爬虫框架,大家可以学习使用!1.Scrapysc...

12个高效的Python爬虫框架,你用过几个?

实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫,为什么呢?因为Python确实很适合做爬虫,丰富的第三方库十分强大,简单几行代码便可实...

pip3 install pyspider报错问题解决

运行如下命令报错:>>>pip3installpyspider观察上面的报错问题,需要安装pycurl。是到这个网址:http://www.lfd.uci.edu/~gohlke...

PySpider框架的使用

PysiderPysider是一个国人用Python编写的、带有强大的WebUI的网络爬虫系统,它支持多种数据库、任务监控、项目管理、结果查看、URL去重等强大的功能。安装pip3inst...

「机器学习」神经网络的激活函数、并通过python实现激活函数

神经网络的激活函数、并通过python实现whatis激活函数感知机的网络结构如下:左图中,偏置b没有被画出来,如果要表示出b,可以像右图那样做。用数学式来表示感知机:上面这个数学式子可以被改写:...