[读书日志]从零开始学习Chisel 第二篇:Scala的变量与函数(敏捷硬件开发语言Chisel与数字系统设计)

第一篇icon-default.png?t=O83Ahttps://blog.csdn.net/m0_74021449/article/details/144887921

2.2 Scala的变量及函数

2.2.1变量定义与基本类型

变量声明

变量首次定义必须使用关键字var或者val,二者的区别是val修饰的变量禁止被重新赋值,它是一个只读的变量。首次定义变量时必须赋值进行初始化。var类型的变量重新赋值时新旧必须是同一个类型,而val类型变量无法被重新赋值。变量定义具有覆盖性,后声明的变量会覆盖前面的变量。

Scala推荐使用val定义变量,函数式编程的思想之一就是传入函数的参数不应该改变。需要说明的是,使用val定义的变量并不是不可变,而是这个指向关系不可变。当这个变量被声明,变量指向的对象就是唯一确定的,但这个对象本身可以改变,只是变量指向的位置不可变。

基本类型

Scala作为一种静态语言,在编译时会检查每个对象的类型,类型不匹配的非法操作会报错。Scala定义了一些标准类型:

类型说明
Byte8bit有符号整数,补码表示,范围是-27~27-1
Short16bit有符号整数,补码表示,范围是-215~215-1
Int32bit有符号整数,补码表示,范围是-231~231-1
Long64bit有符号整数,补码表示,范围是-263~263-1
Char16bit无符号字符,Unicode编码表示,范围是0~216-1
String字符串类型,属于java.bang包
Float32bit单精度浮点数
Double64bit双精度浮点数
Boolean布尔值,true or false

定义变量时可以指定类型,也可以让编译器自动推断。显式指定类型的示例:

scala> val x: Int = 123
val x: Int = 123scala> val y: Long = 123
val y: Long = 123

整数字面量

如果单独出现数字,没有任何说明,默认推断为Int类型;结尾有l或L的推断为Long类型,以0x开头的认为是十六进制,不区分大小写。Byte和Short类型需要显示指定:

scala> val x = 100
val x: Int = 100
​
scala> val y = 100L
val y: Long = 100
​
scala> val z: Byte = 200
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val z: Byte= 200|             ^^^|             Found:    (200 : Int)|             Required: Byte|| longer expla

Byte类型最大不超过127,超过限制的赋值将报错

浮点数字面量

浮点数字面量都是十进制的,默认是Double类型,En或en表示科学计数法10的n次方,末尾加一个f或F表示Float,D或d表示Double。Double字面量不能赋值给Float类型变量。

scala> val x: Float = -3.2
val x: Float = -3.2
​
scala> val x = -3.2
val x: Double = -3.2
​
scala> val x: Float = 3.2D
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val x: Float = 3.2D|               ^^^^|               Found:    (3.2d : Double)|               Required: Float|| longer explanation available when compiling with `-explain`
1 error found

字符字面量和字符串字面量

以单引号括住的一个字符表示一个字符字面量,采用Unicode编码,也可以使用'\u编号'来构建一个字符,本书说明Unicode编码可以出现在名称命名处,但在最新版本Scala编译器中会报错:

scala> val a = 'a'
val a: Char = a
​
scala> val \u0041 = 'a'
-- [E032] Syntax Error: ------------------------------------------------------------------------------------------------
1 |val \u0041 = 'a'|           ^|           pattern expected|| longer explanation available when compiling with `-explain`

字符串字面量是用双引号“”括住的字符序列,长度是任意的。字符和字符串都支持转义字符。

字符串插值

表达式可以被嵌入在字符串字面量中被求值,有三种实现方法,一种是s插值器,一种是raw插值器,一种是f插值器。

s插值器形如 s"……${表达式}……"其中花括号可以不加,但只会识别美元符号到首个非标识字符(字母、数字、下划线和操作符的组合交标识符,以及字符串)对于非标识字符如果想要求值,必须使用花括号:

scala> val name = "Jia"
val name: String = Jiascala> s"Name = $name"
val res3: String = Name = Jiascala> s"Result = ${1+2}"
val res4: String = Result = 3

raw插值器和s插值器类似,区别是不识别转义字符。

f插值器使用方法更灵活,支持格式控制:

scala> printf(f"${math.Pi}%.5f")
3.14159~

2.2.2函数及其几种形式

函数的定义

不多说,直接看代码:

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

说明:x,y是输入参数(形参)后面跟的是它们的类型;Int={}是函数体,表示返回是一个Int类型整数。

备注:左侧的|只是编译器自己生成的,用于多行的代码,并不是语法体系中的一部分。

  1. 分号推断:语句末尾的分号是可选的,编译器会自动推断分号。如果一行有多条语句,则必须用分号隔开。

  2. 函数的返回结果:return关键字是可选的,编译器自动为函数体中的最后一个表达式加上return,建议不要显示声明return。返回结果的类型也可以自动推断,也就是说上面的Int = {},Int也是可以省略的。Uint类型表示无返回值,它不是必须的,编译器也可以自动推断;但如果显式声明Uint,则即便有可以返回的值也不会返回任何值。

  3. 等号与函数体:函数体是花括号括起来的部分,里面有多条语句,可以自动推断分号,返回最后一个表达式。当函数的返回类型没有显示声明,等号可以省略,但此时返回类型会变成Uint,建议不要省略等号,并且用显示声明返回类型。

  4. 无参函数:无参函数可以写空括号作为参数列表,也可以不写;但如果没有空括号,调用的时候禁止写空括号。

方法

方法指定义在class,object,trait中的函数,成为成员函数或方法,这与其他面向对象特性的语言一致。

嵌套函数

函数体内部可以嵌套定义内部函数,但无法被外界访问。

函数字面量

函数式编程认为函数的地位和一个Int值,String值是一样的,因此函数也可以成为一个函数的参数或返回值,也可以把函数赋值给一个变量。函数字面量是一种匿名函数,它可以存储在变量中,成为函数参数,或者当作返回值返回,定义形式是:

{参数1:参数1类型,参数2:参数2类型...} => {函数体}

它可以更精简地使用,用下划线作为占位符替代参数,只保留函数体:

scala> val f = (_: Int) + (_: Int)
val f: (Int, Int) => Int = Lambda/0x00000003015d55a8@6816b0cbscala> f(1,2)
val res5: Int = 3

用def定义的函数和函数字面量都可以以函数为参数,返回函数。

scala> val add = (x:Int) => {(y:Int) => x + y}
val add: Int => Int => Int = Lambda/0x00000003015d6348@20f1e26scala> add(1)(10)
val res6: Int = 11

这里是函数的嵌套,第一个函数表示输入是x,类型是Int,函数体是(y:Int)=> x+y这是一个函数字面量,它的输入是y,类型是Int,函数体是x+y,并且把这个表达式结果返回。如果调用add(1),则返回的是(y:Int)=>1+y这个函数字面量。

scala> def aFunc(f:Int => Int) = f(1) + 1
def aFunc(f: Int => Int): Int
​
scala> aFunc(x=>x+1)
val res7: Int = 3

aFunc的参数f是一个函数,它的输入类型是Int,返回类型也是Int,调用时传入的参数是函数字面量x=>x+1,首先计算f(1)=2,再计算返回值是3。

部分应用函数

上面的函数字面量实现了函数作为一等值的功能,使用def定义的函数也具有相同的功能,只不过需要借助部分应用函数的形式来实现。部分应用函数的意思就是给出函数的一部分参数,使其可以赋值给变量或者当作函数参数进行传递。废话不多数,直接上代码:

scala> def sum(x:Int,y:Int,z:Int) : Int = {x + y + z}
def sum(x: Int, y: Int, z: Int): Int
​
scala> val a1 = sum(4,5,6)
val a1: Int = 15
​
scala> val a2 = sum(4,_:Int,6)
val a2: Int => Int = Lambda/0x000000030167d3a0@c3acda3
​
scala> a2(5)
val res12: Int = 15
​
scala> val a3 = sum _
1 warning found
-- Warning: ------------------------------------------------------------------------------------------------------------
1 |val a3 = sum _|         ^^^^^|         The syntax `<function> _` is no longer supported;|         you can simply leave out the trailing ` _`
val a3: (Int, Int, Int) => Int = Lambda/0x00000003016767e0@2c427287
​
scala> val a3 = sum
val a3: (Int, Int, Int) => Int = Lambda/0x0000000301676e10@68603829
​
scala> a3(4,5,6)
val res9: Int = 15

注意:书中的写法 sum _在最新版的编译器中不被支持,现在无需写下划线,只需要把函数名直接赋值给变量即可直接调用。

scala> def needSum(f:(Int,Int,Int) => Int) = f(1,2,3)
def needSum(f: (Int, Int, Int) => Int): Int
​
scala> needSum(sum)
val res13: Int = 6

这里我们已经逐渐能够感受到函数式编程的魅力,当理解这种调用方式后将会有很灵活的应用。

闭包

一个函数除了使用它的参数以外,还可以使用定义在函数以外的其他变量,其中函数的参数成为绑定变量,函数以外的变量称为自由变量,这样的函数称为闭包。函数捕获的自由变量是函数定义之前的自由变量,若后面出现新的同名自由变量将前面的自由变量将其覆盖,函数与其无关。但如果自由变量是用var创建的可变对象,那么闭包随之改变。

scala> var a1 = 1
var a1: Int = 1
​
scala> val a2 = 100
val a2: Int = 100
​
scala> val add1 = (x : Int) => x + a1
val add1: Int => Int = Lambda/0x000000030167fb08@23b456ac
​
scala> val add2 = (x : Int) => x + a2
val add2: Int => Int = Lambda/0x00000003016843f0@525b416f
​
scala> add1(1)
val res14: Int = 2
​
scala> add2(1)
val res15: Int = 101
​
scala> a1 = 100
a1: Int = 100
​
scala> add1(1)
val res16: Int = 101
​
scala> var a1 = 1
var a1: Int = 1
​
scala> add1(1)
val res17: Int = 101
​
scala> val a2 = 1
val a2: Int = 1
​
scala> add2(1)
val res18: Int = 101

阅读这段程序的对比已经很明显地了解到它的性质。在后面改变var变量的值,闭包随之改变,但对于var和val变量重新定义将前面的覆盖,闭包的值不会随之改变。

函数的特殊调用形式

  1. 具名参数:函数调用时传入的参数是按照先后顺序传递的,但如果显式声明参数的名字,可以无视参数顺序。按位置传递的参数和按名字传递的参数可以混用。

  2. 默认参数值:函数定义时可以给参数一个默认值,如果调用函数缺省了这个参数,会使用默认值。

  3. 重复参数:允许把函数的最后一个参数标记为重复参数,形式在最后一个参数的类型后面加上星号。

柯里化

对于大多数编程语言而言,函数只能有一个参数列表,但是列表中可以有若干用逗号间隔的参数。Scala的特性柯里化允许一个函数可以有任意个参数列表,它与另一个语法搭配使用,即当参数列表中只有一个参数时,调用该函数时允许单个参数不用圆括号括起来,改用花括号也可以。

scala> def add(x:Int)(y:Int)(z:Int) = x+y+z
def add(x: Int)(y: Int)(z: Int): Intscala> add(1)
val res19: Int => Int => Int = Lambda/0x0000000301686b40@7ece1800scala> add(1)(2)
val res20: Int => Int = Lambda/0x00000003016872f0@3b3e9814scala> add(1)(2)(3)
val res21: Int = 6scala> add(1)(2){3}
val res22: Int = 6scala> add{1}(2)(3)
val res23: Int = 6

在这里我们看出来其实柯里化就是把它处理成了一个嵌套的函数。

传名参数

如果一个函数是无参函数,调用函数时,传递进去的函数字面量可以只写函数体。

//常规调用方法
scala> val a1 = 1
val a1: Int = 1
​
scala> val a2 = 2
val a2: Int = 2
​
scala> def add(f: () => Int) = {a1 + a2 + f()}
def add(f: () => Int): Int
​
scala> add(() => 1)
val res24: Int = 4
​
//传名参数调用方法
scala> def add2(f: => Int) = {a1 + a2 + f}
def add2(f: => Int): Int
​
scala> add2(1)
val res26: Int = 4

注:这里传入的f函数是一个没有输入,直接返回传入的值的函数。

这两种版本都是在使用到传入的函数时才会计算这个函数中的表达式,但如果改写成下面这样:(去掉=>),那么就变成先计算表达式再传入值。

scala> def add3(f:Boolean) = {| if(f)| a1 + a2| else| 0| }
def add3(f: Boolean): Int
​
scala> add3(1<2)
val res27: Int = 3
​
scala> add3(1>2)
val res28: Int = 0
​
scala> add3(1/0)
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |add3(1/0)|     ^^^|     Found:    Int|     Required: Boolean|| longer explanation available when compiling with `-explain`
1 error found

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/66271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot - 日志功能深度解析与实践指南

文章目录 概述1. Spring Boot 日志功能概述2. 默认日志框架&#xff1a;LogbackLogback 的核心组件Logback 的配置文件 3. 日志级别及其配置配置日志级别3.1 配置文件3.2 环境变量3.3 命令行参数 4. 日志格式自定义自定义日志格式 5. 日志文件输出6. 日志归档与清理7. 自定义日…

NVIDIA DLI课程《NVIDIA NIM入门》——学习笔记

先看老师给的资料&#xff1a; NVIDIA NIM是 NVIDIA AI Enterprise 的一部分&#xff0c;是一套易于使用的预构建容器工具&#xff0c;目的是帮助企业客户在云、数据中心和工作站上安全、可靠地部署高性能的 AI 模型推理。这些预构建的容器支持从开源社区模型到 NVIDIA AI 基础…

【HF设计模式】05-单例模式

声明&#xff1a;仅为个人学习总结&#xff0c;还请批判性查看&#xff0c;如有不同观点&#xff0c;欢迎交流。 摘要 《Head First设计模式》第5章笔记&#xff1a;结合示例应用和代码&#xff0c;介绍单例模式&#xff0c;包括遇到的问题、采用的解决方案、以及达到的效果。…

【FlutterDart】页面切换 PageView PageController(9 /100)

上效果&#xff1a; 有些不能理解官方例子里的动画为什么没有效果&#xff0c;有可能是我写法不对 后续如果有动画效果修复了&#xff0c;再更新这篇&#xff0c;没有动画效果&#xff0c;总觉得感受的丝滑效果差了很多 上代码&#xff1a; import package:flutter/material.…

Electron快速入门——跨平台桌面端应用开发框架

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

Android NDK开发实战之环境搭建篇(so库,Gemini ai)

文章流程 音视频安卓开发首先涉及到ffmpeg编译打包动态库&#xff0c;先了解动态库之间的cpu架构差异性。然后再搭建可运行的Android 环境。 So库适配 ⽇常开发我们经常会使⽤到第三库&#xff0c;涉及到底层的语⾳&#xff0c;视频等都需要添加so库。⽽so库的体积⼀般来说 ⾮…

【Java回顾】Day2 正则表达式----异常处理

参考资料&#xff1a;菜鸟教程 https://www.runoob.com/java/java-exceptions.html 正则表达式 有一部分没看完 介绍 字符串的模式搜索、编辑或处理文本java.util.regex包&#xff0c;包含了pattern和mathcer类&#xff0c;用于处理正则表达式的匹配操作。 捕获组 把多个字符…

Unity性能优化总结

目录 前言 移动端常见性能优化指标​编辑 包体大小优化 FPS CPU占用率 GPU占用率 内存 发热和耗电量 流量优化 前言 终于有时间了&#xff0c;我将在最近两个项目中进行优化的一些经验进行归纳总结以飨读者。因为我习惯用思维导图&#xff0c;所以归纳的内容主要以图来…

北京航空航天大学惊现技术商业“宫斗剧”!背后隐藏的内幕遭曝光!

北京航空航天大学&#xff08;以下称北航&#xff09;与源亿&#xff08;北京&#xff09;网络科技有限公司&#xff08;以下称源亿&#xff09;的派驻的员工恶意串通&#xff0c;指定北京蚂蚁非标科技有限公司&#xff08;以下称蚂蚁公司&#xff09;挖走源亿公司在现场派驻的…

transfomer深度学习实战水果识别

本文采用RT-DETR作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。RT-DETR以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对水果数据集进行训练和优化&#xff0c;该数据集包含丰富的水果图像样本&#…

TensorFlow深度学习实战(3)——深度学习中常用激活函数详解

TensorFlow深度学习实战&#xff08;3&#xff09;——深度学习中常用激活函数详解 0. 前言1. 引入激活函数1.1 感知器1.2 多层感知器1.3 训练感知器存在的问题 2. 激活函数3. 常见激活函数3.1 sigmoid3.2 tanh3.3 ReLU3.4 ELU和Leaky ReLU 小结系列链接 0. 前言 使用激活函数…

数据结构C语言描述9(图文结合)--二叉树和特殊书的概念,二叉树“最傻瓜式创建”与前中后序的“递归”与“非递归遍历”

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法&#xff1b;有C基础即可跟着学习&#xff0c;代码均可运行&#xff1b;准备考研的也可跟着写&#xff0c;个人感觉&#xff0c;如果时间充裕&#xff0c;手写一遍比看书、刷题管用很多&#xff0c;这也是本人采用纯C语言…

Leetcode打卡:设计一个ATM机器

执行结果&#xff1a;通过 题目 2241 设计一个ATM机器 一个 ATM 机器&#xff0c;存有 5 种面值的钞票&#xff1a;20 &#xff0c;50 &#xff0c;100 &#xff0c;200 和 500 美元。初始时&#xff0c;ATM 机是空的。用户可以用它存或者取任意数目的钱。 取款时&#xff0c…

vscode如何离线安装插件

在没有网络的时候,如果要安装插件,就会麻烦一些,需要通过离线安装的方式进行。下面记录如何在vscode离线安装插件。 一、下载离线插件 在一台能联网的电脑中,下载好离线插件,拷贝到无法联网的电脑上。等待安装。 vscode插件商店地址:https://marketplace.visualstudio.co…

用Tkinter制作一个用于合并PDF文件的小程序

需要安装PyPDF2库&#xff0c;具体原代码如下&#xff1a; # -*- coding: utf-8 -*- """ Created on Sun Dec 29 14:44:20 2024author: YBK """import PyPDF2 import os import tkinter as tk import windndpdf_files [] def dragged_files(f…

CDP集成Hudi实战-Hive

[〇]关于本文 本文测试一下使用Hive和Hudi的集成 软件版本Hudi1.0.0Hadoop Version3.1.1.7.3.1.0-197Hive Version3.1.3000.7.3.1.0-197Spark Version3.4.1.7.3.1.0-197CDP7.3.1 [一]部署Jar包 1-部署hudi-hive-sync-bundle-1.0.0.jar文件 [rootcdp73-1 ~]# for i in $(se…

公司资产网站

本文结尾处获取源码。 本文结尾处获取源码。 本文结尾处获取源码。 一、相关技术 后端&#xff1a;Java、JavaWeb / Springboot。前端&#xff1a;Vue、HTML / CSS / Javascript 等。数据库&#xff1a;MySQL 二、相关软件&#xff08;列出的软件其一均可运行&#xff09; I…

CSS——2.书写格式一

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><!--css书写中&#xff1a;--><!--1.css 由属性名:属性值构成--><!--style"color: red;font-size: 20px;&quo…

基于FPGA的辩论赛系统设计-8名选手-正反两方-支持单选手评分-正反两方评分总和

基于FPGA的辩论赛系统设计 功能描述一、系统概述二、仿真波形视频 功能描述 1.答辩倒计时功能&#xff0c;当正反任意一方开始答辩后&#xff0c;倒计时30S。在倒计时最后10S后&#xff0c;LED灯开始闪烁。 2.答辩评分和计分功能&#xff0c;当答辩方结束答辩后&#xff0c;评…

【OceanBase】使用 Superset 连接 OceanBase 数据库并进行数据可视化分析

文章目录 前言一、前提条件二、操作步骤2.1 准备云主机实例2.2 安装docker-compose2.3 使用docker-compose安装Superset2.3.1 克隆 Superset 的 GitHub 存储库2.3.2 通过 Docker Compose 启动 Superset 2.4 开通 OB Cloud 云数据库2.5 获取连接串2.6 使用 Superset 连接 OceanB…