重要

变量和函数应该定义为``object``,classfunction。您不能在根目录下的 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

继承

举个例子,假设您要定义两个类,RectangleSquare,它们扩展了 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 classclass 之间有下面区别:

  • 样例类不需要 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() }