欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 资讯 > [读书日志]从零开始学习Chisel 第九篇:Scala的内建控制结构(敏捷硬件开发语言Chisel与数字系统设计)

[读书日志]从零开始学习Chisel 第九篇:Scala的内建控制结构(敏捷硬件开发语言Chisel与数字系统设计)

2025/1/14 0:38:13 来源:https://blog.csdn.net/m0_74021449/article/details/145019831  浏览:    关键词:[读书日志]从零开始学习Chisel 第九篇:Scala的内建控制结构(敏捷硬件开发语言Chisel与数字系统设计)

6.Scala的内建控制结构

6.1 if表达式

和大部分编程语言的if表达式使用上没有区别,单句话不需要加花括号,多个语句需要加花括号,直接来看一段代码:

scala> def whichInt(x:Int) = {| if(x == 0) "Zero"| else if(x > 0) "Positive Number"| else "Negative Number"| }
def whichInt(x: Int): Stringscala> whichInt(-1)
val res33: String = Negative Number
6.2 while循环

while循环的使用方法与C语言类似,有while型循环和do...while型循环,直接来看下面的代码:

scala> def fac_loop(num:Int): Int = {| var res: Int = 1| var num1: Int = num| while(num1 != 0) {| res *= num1| num1 -= 1| }| res| }
def fac_loop(num: Int): Intscala> fac_loop(5)
val res34: Int = 120

while的风格是指令式的,if被称为表达式,因为它可以返回有用的值,而while被称为循环,因为它不会返回有用的值。Scala兼容这种形式,因为它看起来更容易阅读。实际上所有的while循环都可以通过其他函数式风格来实现,常用的各式函数的自我递归调用。例如将上面的函数重写为如下,它是一个函数式风格的求阶乘函数:

scala> def fac(num:Int): Int =| if (num == 1) 1 else num*fac(num-1)
def fac(num: Int): Intscala> fac(5)
val res35: Int = 120
6.3 for表达式与for循环

实现循环,推荐使用for循环。for循环是函数式风格的,而没有引入指令式风格。它的一般形式如下:

for(seq) yield expression,整个for表达式算一个语句,在这里seq代表一个序列。能放进for表达式中的对象必须是一个可迭代的集合,如常用列表,数组,映射,区间,迭代器,流和所有的集,它们都混入了特质Iterableyield是产生的意思,表示把前面序列中符合条件的元素拿出来,逐个应用到后面的表达式中,得到的所有结果按顺序形成一个新的集合对象。将seq展开来是这样的:

for {p <- persons			//一个生成器n = p.name				//一个定义if(n startWith "To")	//一个过滤器
} yield n

seq是由生成器,定义,过滤器三条语句组成的,以分号隔开或者放在花括号中自动推断分号。

生成器p -> person右侧是一个可迭代的集合对象,把它的每个元素逐一拿出来与左侧的模式进行匹配(模式匹配见后面的章节)如果匹配成功,那么模式中的遍历就会绑定上该元素的对于部分;如果匹配失败,则直接丢弃该元素。在这个例子中,p是一个无需定义的变量名,它构成了变量模式,简单地指向person的每个元素。

定义就是一个赋值语句,这里的n也是一个无须定义的变量名。定义并不常用,可有可无。

过滤器是一个if语句,只有它后面的表达式为真时生成器的元素才会向后传递,否则丢弃这个元素。在这里是判断person的元素的name字段是否以“To”开头。

编写以下的test.scala文件:

class Person(val name: String)object Alice extends Person("Alice")
object Tom extends Person("Tom")
object Tony extends Person("Tony")
object Bob extends Person("Bob")
object Todd extends Person("Todd")val persons = List(Alice, Tom, Tony, Bob, Todd)val To = for {p <- personsn = p.nameif(n.startsWith("To"))
} yield n@main def test() = println(To)

注意,刚才像上面原书上的写法会导致警告。对于没有被声明@infix的方法,推荐使用句点调用方法。编译后输出如下:

jia@J-MateBookEGo:~/scala_test$ scala test.scala
Compiling project (Scala 3.6.2, JVM (21))
Compiled project (Scala 3.6.2, JVM (21))
List(Tom, Tony, Todd)

for循环表达式都从生成器开始,如果一个for表达式中有多个生成器,就成为嵌套的for循环。

scala> for {| i <- 1 to 9| j <- 1 to 9| } yield i*j
val res0: IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 4, 6, 8, 10, 12, 14, 16, 18, 3, 6, 9, 12, 15, 18, 21, 24, 27, 4, 8, 12, 16, 20, 24, 28, 32, 36, 5, 10, 15, 20, 25, 30, 35, 40, 45, 6, 12, 18, 24, 30, 36, 42, 48, 54, 7, 14, 21, 28, 35, 42, 49, 56, 63, 8, 16, 24, 32, 40, 48,56, 64, 72, 9, 18, 27, 36, 45, 54, 63, 72, 81)

这是99乘法表的生成代码。每当生成器生成一个匹配的元素,后面的定义会重新求值。如果后面的定义与生成器元素的值无关,尽量将定义写在外面。如果只是把每个元素应用到一个Uint类型的表达式,则是一个for循环,不是for表达式,关键字yield也可以省略:

scala> var sum = 0
var sum: Int = 0scala> for(x <- 1 to 100) sum += xscala> sum
val res1: Int = 5050
6.4 用try表达式处理异常
6.4.1抛出一个异常

可以用new构造一个异常对象,并用关键字throw手动抛出异常:

scala> throw new IllegalArgumentException
java.lang.IllegalArgumentException... 30 elided
6.4.2 try-catch

try后面可以用花括号包含任意条代码,当这些代码产生异常时,JVM不会立即抛出,而是被catch捕获,catch捕获异常后,按其后面的定义进行相应的处理。

scala> def intDivision(x:Int, y:Int) = {| try {| x / y| } catch {| case ex: ArithmeticException => println("The divisor is Zero!")| }| }
def intDivision(x: Int, y: Int): Int | Unitscala> intDivision(10,0)
The divisor is Zero!
val res3: Int | Unit = ()
6.4.3 finally

try表达式的完整形式是try-catch-finally,无论有没有异常产生,finally中的代码都会执行。通常它的作用是执行一些清理工作,比如关闭文件。try表达式可以返回有用值,但尽量避免这样的做法。

6.5 match表达式

match表达式作用类似于switch,是把作用对象与定义的模式逐个比较,按匹配的模式执行相应的操作。

scala> def something(x: String) = x match {| case "Apple" => println("Fruit!")| case "Tomato" => println("Vegetable!")| case "Cola" => println("Beverage!")| case _ => println("Huh?")| }
def something(x: String): Unitscala> something("Cola")
Beverage!scala> something("Toy")
Huh?
6.6 关于conyinue和break

一言以蔽之,这是指令式编程常用的关键字,但它们并不是必须的。使用导入库的方法可以使用,但Scala不推荐使用这两个关键字,需要通过自己修改代码实现其他的方案。

6.7 关于变量的作用域

变量的作用域是以花括号为边界的,重名的情况下优先使用内部变量,超出内部变量的范围则使用外部变量。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com