重要
变量和函数应该定义为``object``,class
,function
。您不能在根目录下的 Scala 文件中定义它们。
基础内容
类型
在Scala中,主要有5种类型:
类型 |
形式 |
描述 |
---|---|---|
Boolean |
true, false |
|
Int |
3, 0x32 |
32 位整数 |
Float |
3.14f |
32 位浮点数 |
Double |
3.14 |
64位浮点 |
String |
“Hello world” |
UTF-16 字符串 |
变量
在 Scala 中,您可以使用 var 关键字定义变量:
var number : Int = 0
number = 6
number += 4
println(number) // 10
Scala 能够自动推断类型。如果变量是在声明时赋值的,则不需要指定类型:
var number = 0 // The type of 'number' is inferred as an Int during compilation.
然而,在 Scala 中使用 var 并不常见。相反,经常使用由 val
定义的常量值:
val two = 2
val three = 3
val six = two * three
函数
例如,如果你想定义一个函数,当两个参数之和大于零时返回 true
,你可以这样做:
def sumBiggerThanZero(a: Float, b: Float): Boolean = {
return (a + b) > 0
}
然后,要调用该函数,您可以编写:
sumBiggerThanZero(2.3f, 5.4f)
您还可以按名称指定参数,如果您有很多参数,这会很有用:
sumBiggerThanZero(
a = 2.3f,
b = 5.4f
)
返回类型
return
关键字不是必需的。如果没有它,Scala 会将函数的最后一条语句作为返回值。
def sumBiggerThanZero(a: Float, b: Float): Boolean = {
(a + b) > 0
}
返回类型推断
Scala 能够自动推断返回类型。您不需要指定它:
def sumBiggerThanZero(a: Float, b: Float) = {
(a + b) > 0
}
大括号
如果您的函数仅包含一条语句,则 Scala 函数不需要大括号:
def sumBiggerThanZero(a: Float, b: Float) = (a + b) > 0
不返回任何内容的函数
如果您希望函数不返回任何内容,则返回类型应设置为 Unit
。它相当于 C/C++ void
类型。
def printer(): Unit = {
println("1234")
println("5678")
}
参数默认值
您可以为函数的每个参数指定默认值:
def sumBiggerThanZero(a: Float, b: Float = 0.0f) = {
(a + b) > 0
}
Apply函数
名为 apply
的函数很特殊,因为您无需输入名称即可调用它们:
class Array() {
def apply(index: Int): Int = index + 3
}
val array = new Array()
val value = array(4) // array(4) is interpreted as array.apply(4) and will return 7
这个概念也适用于 Scala ``object``(静态)
object MajorityVote {
def apply(value: Int): Int = ...
}
val value = MajorityVote(4) // Will call MajorityVote.apply(4)
对象(Object)
在 Scala 中,没有 static
关键字。取而代之的是 object
。在 object
定义中所有内容都是静态的。
以下示例定义了一个名为 pow2
的静态函数,它接受浮点值作为参数并返回浮点值。
object MathUtils {
def pow2(value: Float): Float = value * value
}
然后你可以这样来调用它:
MathUtils.pow2(42.0f)
入口点(main)
Scala 程序的入口点(主函数)应在对象内部定义为名为 main
的函数。
object MyTopLevelMain {
def main(args: Array[String]) {
println("Hello world")
}
}
类
类的语法与Java非常相似。想象一下,您想要定义一个 Color
类,它将三个 Float 值 (r,g,b) 作为构造函数的参数:
class Color(r: Float, g: Float, b: Float) {
def getGrayLevel(): Float = r * 0.3f + g * 0.4f + b * 0.4f
}
然后,实例化上一个示例中的类并使用其 getGrayLevel
函数:
val blue = new Color(0, 0, 1)
val grayLevelOfBlue = blue.getGrayLevel()
注意,如果你想从外部访问类的构造参数,那么这个参数应该定义为 val
:
class Color(val r: Float, val g: Float, val b: Float) { ... }
...
val blue = new Color(0, 0, 1)
val redLevelOfBlue = blue.r
继承
举个例子,假设您要定义两个类,Rectangle
和 Square
,它们扩展了 Shape
类:
class Shape {
def getArea(): Float
}
class Square(sideLength: Float) extends Shape {
override def getArea() = sideLength * sideLength
}
class Rectangle(width: Float, height: Float) extends Shape {
override def getArea() = width * height
}
样例类
样例类是声明类的另一种方式。
case class Rectangle(width: Float, height: Float) extends Shape {
override def getArea() = width * height
}
case class
和 class
之间有下面区别:
样例类不需要
new
关键字来实例化。构造参数可从外部获取;你不需要将它们定义为
val
。
在 SpinalHDL 中,这解释了编码约定背后的原因:通常建议使用``case class`` 而不是 class
,以减少代码量并提高一致性。
模板/类型参数化
想象一下,您想要设计一个类,它是某数据类型的队列,在这种情况下,您需要向该类提供类型参数:
class Queue[T]() {
def push(that: T) : Unit = ...
def pop(): T = ...
}
如果你想将 T
类型限制为给定类型的子类(例如 Shape
),你可以使用 <: Shape
语法:
class Shape() {
def getArea(): Float
}
class Rectangle() extends Shape { ... }
class Queue[T <: Shape]() {
def push(that: T): Unit = ...
def pop(): T = ...
}
对于函数来说也是如此:
def doSomething[T <: Shape](shape: T): Something = { shape.getArea() }