1

[2]SpinalHDL教程——Scala简单入门 - msuad

 1 year ago
source link: https://www.cnblogs.com/msuad/p/17335201.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

第一个 Scala 程序#

shell里面输入

$ scala
scala> 1 + 1
res0: Int = 2

scala> println("Hello World!")
Hello World!
object HelloWorld {
   /* 这是我的第一个 Scala 程序
    * 以下程序将输出'Hello World!'
    */
   def main(args: Array[String]) = {
      println("Hello, world!") // 输出 Hello World
   }
}

接下来我们使用 scalac 命令编译它:

$ scalac HelloWorld.scala 
$ ls
HelloWorld$.class    HelloWorld.scala
HelloWorld.class    

编译后我们可以看到目录下生成了 HelloWorld.class 文件,该文件可以在Java Virtual Machine (JVM)上运行。

编译后,我们可以使用以下命令来执行程序:

$ scala HelloWorld
Hello, world!

基本语法#

Scala是运行在jvm上面的一款语言,在语法和概念上难免和java会有相似之处,而java的语法和C语法一脉相承,所以有C基础的话基本语法还是比较好上手的。

Scala有两个设计理念:面向对象(OOP)和函数式编程(FP)

面向对象就导致Scala中万物皆对象;函数式这个概念比较陌生,后续会单独介绍。

1.变量#

使用关键词 "var" 声明变量,使用关键词 "val" 声明常量。

声明变量实例如下:

var myVar : String = "Foo"
var myVar : String = "Too"

Scala是一个静态类型语言,但编译器能自动推断类型

所以上面能这么写,效果一样:

var myVar = "Foo"
var myVar = "Too"

2.数据类型#

然而,我们说scala是一款万物皆对象的语言,这些变量都是对象

这就类似于java中的封装类(Scala的底层实现确实也是用的java的封装类)

Scala 与 Java有着相同的数据类型,下表列出了 Scala 支持的数据类型:

数据类型 描述
Byte 8位有符号补码整数。数值区间为 -128 到 127
Short 16位有符号补码整数。数值区间为 -32768 到 32767
Int 32位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807
Float 32 位, IEEE 754 标准的单精度浮点数
Double 64 位 IEEE 754 标准的双精度浮点数
Char 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF
String 字符序列
Boolean true或false
Unit 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
Null null 或空引用
Nothing Nothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。
Any Any是所有其他类的超类
AnyRef AnyRef类是Scala里所有引用类(reference class)的基类

上表中列出的数据类型都是对象,也就是说scala没有java中的原生类型。在scala是可以对数字等基础类型调用方法的。

(1)整数字面量、浮点字面量#

(2)字符串字面量#

scala> '1'
res0: Char = 1

scala> "1"
res1: String = 1

scala> "\t"
res2: String = "        "

scala> """\t"""
res3: String = \t

字符串插值,会对每个表达式求值,并且调用toString方法

scala> val a=2.1
a: Double = 2.1

scala> val s=s"Hi,${a+9}!"
s: String = Hi,11.1!

函数#

方法定义#

方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。

Scala 方法定义格式如下:

def functionName ([参数列表]) : [return type] = {
   function body
   return [expr]
}
  • 以上代码中 return type 可以是任意合法的 Scala 数据类型。参数列表中的参数可以使用逗号分隔。

题外话:scala能使用元组进行打包,返回多个变量,在调用时解构赋值

scala> def useScala() = (1,2,3)
useScala: ()(Int, Int, Int)

scala> val a,b,c = useScala()
a: (Int, Int, Int) = (1,2,3)
b: (Int, Int, Int) = (1,2,3)
c: (Int, Int, Int) = (1,2,3)

  • 函数体最后一行的return推荐省略
  • 等号”=“省略条件:返回类型未显式声明,并且返回类型为Unit,这个类似于 Java 的 void, 实例如下:
object Hello{
   def printMe( ){
      println("Hello, Scala!")
   }
}

方法调用#

以下是调用方法的标准格式:

functionName( 参数列表 )

如果方法使用了实例的对象来调用,我们可以使用类似java的格式 (使用 . 号):

[instance.]functionName( 参数列表 )

类和对象#

类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。

class Point(xc: Int, yc: Int) {
   var x: Int = xc
   var y: Int = yc

   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("x 的坐标点: " + x);
      println ("y 的坐标点: " + y);
   }
}

构造方法#

  1. 主构造方法

    在类内部非字段、非方法的部分全部当作构造函数,在类名后参数列表用于接收。

    可以看一个SpinalHDL生成verilog的写法:

    object MyTopLevelVerilog extends App {
      Config.spinal.generateVerilog(MyTopLevel(4))
    }
    

    看到App定义:

    trait App extends DelayedInit {
    
      // ...
        
      @deprecatedOverriding("main should not be overridden", "2.11.0")
      def main(args: Array[String]) = {
        this._args = args
        for (proc <- initCode) proc()
        if (util.Properties.propIsSet("scala.time")) {
          val total = currentTime - executionStart
          Console.println("[total " + total + "ms]")
        }
      }
    }
    
  2. 辅助构造函数

    def this( ... )

    函数内第一句必须调用其他的构造方法this()

  3. 私有主构造方法

    如例所示加上private,构造对象时就不能通过主构造方法创建对象,得用辅助构造方法或工厂方法(用于构造对象的方法)

    class Student private (name: String,n: Int)
    

类继承#

extends关键词

class Child extends Parent{
    //...
}

工厂对象和工厂方法#

如果定义一个专门用来构造某一个类的对象的方法,那么这种方法就被称为“工厂方法”。包含这些工厂方法集合的单例对象,称为“工厂对象”。通常,工厂方法会定义在伴生对象中。尤其是当一系列类存在继承关系时,可以在基类的伴生对象中定义一系列对应的工厂方法。使用工厂方法的好处是可以不用直接使用new来实例化对象,改用方法调用,而且方法名可以是任意的,这样对外隐藏了类的实现细节。

//students. scala
class Students(val name:String,var score:Int){
   def exam(s:Int)=score =s
   override def toString =name +"'s score is "+score +"."
}

object Students {
   def registerStu(name:String,score:Int)=new Students(name,score)
} //registerStu为工厂方法

用“ import Students._ ”导入单例对象后,就能这样使用:

scala>import Students._
scala>val stu =registerStu("Tim",100)
stu:Students =Tim's score is 100.

重写方法#

在函数前面加上关键词override

重写toString方法

class A {
    override def toString = "123456A"
}
val a = new A()
println(a)
scala> class A {
     |     override def toString = "123456A"
     | }
// defined class A

scala> val a = new A()
val a: A = 123456A

scala> println(a)
123456A

Scala 单例对象#

在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。

Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。

当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
   }
}

object Test {
   def main(args: Array[String]) {
      val point = new Point(10, 20)
      printPoint

      def printPoint{
         println ("x 的坐标点 : " + point.x);
         println ("y 的坐标点 : " + point.y);
      }
   }
}

执行以上代码,输出结果为:

$ scalac Test.scala 
$ scala Test
x 的坐标点 : 10
y 的坐标点 : 20

伴生对象#

// 私有构造方法
class Marker private(val color:String) {

  println("创建" + this)
 
  override def toString(): String = "颜色标记:"+ color
 
}

// 伴生对象,与类名字相同,可以访问类的私有属性和方法
object Marker{
 
    private val markers: Map[String, Marker] = Map(
      "red" -> new Marker("red"),
      "blue" -> new Marker("blue"),
      "green" -> new Marker("green")
    )
   
    def apply(color:String) = {
      if(markers.contains(color)) markers(color) else null
    }
 
   
    def getMarker(color:String) = {
      if(markers.contains(color)) markers(color) else null
    }
    def main(args: Array[String]) {
        println(Marker("red"))  
        // 单例函数调用,省略了.(点)符号  
                println(Marker getMarker "blue")  
    }
}

操作符即方法#

  1. 前缀操作符

    只有+、-、、!有,对应的方法名是unary_+、unary_-、unary_、unary_!

    2.中缀和后缀操作符

​ 以冒号结尾的操作符,右操作符是调用对象


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK