scala case class 繼承_數字硬件系統設計之一:Scala快速入門(2)

原想簡單籠統介紹一下scala,后感覺這么做意思不大,網友看了和沒看一樣,還是應該稍微詳細具體一點,故而把系列編號由(上)(中)(下),改為(上)(2)(3)(4)(5)....,(上)就是(1)吧d0c0a7c130b26c177aa7e039923854c2.png,以下內容部分節選于我們即將出版的書稿:

a1627fd33f5d98c000ed1dd91215b031.png

本次推文介紹scala里的類用法:

在Scala里,類是用關鍵字“class”來定義,一旦定義完成,就可以通過“new 類名”的方式來構造一個對象。而這個對象的類型,就是這個類。換句話說,一個類就是一個類型,不同的類就是不同的類型。在后續會講到類的繼承關系,以及超類、子類和子類型多態的概念。

在類里可以定義val或var類型的變量,它們被稱為“字段”;還可以定義“def”函數,它們被稱為“方法”;字段和方法統稱“成員”。字段通常用于保存對象的狀態或數據,而方法則用于承擔對象的計算任務。字段也叫“實例變量”,因為每個被構造出來的對象都有其自己的字段。在運行時,操作系統會為每個對象分配一定的內存空間,用于保存對象的字段。方法則不同,對所有對象來說,方法都是一樣的程序段,因此不需要為某個對象單獨保存其方法。而且,方法的代碼只有在被調用時才會被執行,如果一個對象在生命周期內都沒有調用某些方法,那么完全沒必要浪費內存為某個對象去保存這些無用的代碼。

外部想要訪問對象的成員時,可以使用句點符號“ . ”,通過“對象.成員”的形式來訪問。此外,用new構造出來的對象可以賦給變量,讓變量名成為該對象的一個指代名稱。需要注意的是,val類型的變量只能與初始化時的對象綁定,不能再被賦予新的對象。一旦對象與變量綁定了,便可以通過“變量名.成員”的方式來多次訪問對象的成員。例如:

? ? scala> class Students {

?????????????| ???var name = "None"

?????????????| ???def register(n: String) = name = n

?????????????| ?}

????defined class Students

????scala> val stu = new Students

?stu: Students = Students@1a2e563e

????scala> stu.name

????res0: String = None

????scala> stu.register("Bob")

????scala> stu.name

????res2: String = Bob

????scala> stu = new Students

????:13: error: reassignment to val

???????????stu = new Students

Scala的類成員默認都是公有的,即可以通過“對象.成員”的方式來訪問對象的成員,而且沒有“public”這個關鍵字。如果不想某個成員被外部訪問,則可以在前面加上關鍵字“private”來修飾,這樣該成員只能被類內部的其他成員或上篇提到的伴生對象來訪問,外部只能通過其他公有成員來間接訪問。例如:

????scala> class Students {

?????????????| ???private var name = "None"

?????????????| ???def register(n: String) = name = n

?????????????| ???def display() = println(name)

?????????????| ?}

????defined class Students

????scala> val stu = new Students

????stu: Students = Students@75063bd0

????scala> stu.register("Bob")

????scala> stu.name

????:13: error: variable name in class Students cannot be accessed in Students

???????????stu.name

???? ? ? ? ? ?^

?? ? scala> stu.display

????Bob

類的構造方法

???1、主構造方法

在C++、Java、Python等面向對象語言里,類通常需要定義一個額外的構造方法(構造函數)。這樣,要構造一個類的對象,除了需要關鍵字new,還需要調用構造方法。事實上,這個過程中有一些代碼是完全重復的。Scala則不需要顯式定義構造方法 ,而是把類內部的非字段、非方法的代碼都當作“主構造方法”。而且,類名后面可以定義若干個參數列表,用于接收參數,這些參數將在構造對象時用于初始化字段并傳遞給主構造方法使用。Scala的這種獨特語法減少了一些代碼量。例如:

????scala> class Students(n: String) {

??????????| ???val name = n

??????????| ???println("A student named " + n + " has been registered.")

??????????| ?}

????defined class Students

????scala> val stu = new Students("Tom")

????A student named Tom has been registered.

????stu: Students = Students@5464eb28

在這個例子中,Students類接收一個String參數n,并用n來初始化字段name。這樣做,就無需像之前那樣把name定義成var類型,而是使用函數式風格的val類型,而且不再需要一個register方法在構造對象時來更新name的數據。

函數println既不是字段,也不是方法定義,"= n"也不是字段,也不是方法定義,所以都被當成是主構造函數的一部分。在構造對象時,主構造函數被執行,因此在解釋器里會打印了相關信息。

???2、輔助構造方法

除了主構造方法,scala還可以定義若干個輔助構造方法。輔助構造方法都是以“def this(..)”來開頭的,而且第一步行為必須是調用該類的另一個構造方法,即第一條語句必須是“this(...)”——要么是主構造方法,要么是之前的另一個輔助構造方法。這種規則的結果就是任何構造方法最終都會調用該類的主構造方法(而主構造方法其實就是類定義本身),使得主構造方法成為類的單一入口。例如:

????scala> class Students(n: String) {

????????|val name = n

????????|def this() = this("None")?//輔助構造方法是無參數的,其內部調用主構造方法

????????|println("A student named " + n + " has been registered.")

????????| ?}

????defined class Students

? ? scala> val stu = new Students

????A student named None has been registered.

????stu: Students = Students@64105ca4

在這個例子中,定義了一個輔助構造方法,該方法是無參的,其行為也僅是給主構造方法傳遞一個字符串“None”。

定義此輔助構造方法的作用:當創建該類的實例對象時,如果缺省了參數,這樣與主構造方法的參數列表是不匹配的,但是與輔助構造方法匹配,則系統會使用stu的輔助構造方法構造該實例對象。

Scala只允許主構造方法調用超類的構造方法,不允許輔助構造函數調用超類的構造方法(后續具體講解)。這種限制源于Scala為了代碼簡潔性與簡單性做出的折衷處理。

???3、無析構函數

因為Scala沒有指針,同時使用了Java的垃圾回收器,所以不需要像C++那樣定義析構函數。

???4、私有主構造方法

如果在類名與類的參數列表之間加上關鍵字“private”,那么主構造方法就是私有的,只能被內部定義的輔助構造函數訪問,外部代碼實列化對象時就不能通過主構造方法進行,而必須使用其他公有的輔助構造方法或工廠方法(專門用于構造對象的方法)。例如:

????scala> class Students private (n: String, m: Int) {

?????????????| ???val name = n

?????????????| ???val score = m

?????????????| ???def this(n: String) = this(n, 100)

?????????????| ???println(n + "'s score is " + m)

?????????????| ?}

????defined class Students

????scala> val stu = new Students("Bill", 90)?//與私有的主構造方法匹配,訪問錯誤

????:12: error: too many arguments (2) for constructor Students: (n: String)Students

???????????val stu = new Students("Bill", 90)

????scala> val stu = new Students("Bill") //與輔助構造方法匹配

????Bill's score is 100

????stu: Students = Students@7509b8e7

方法重載

如果在類里定義了多個同名的方法,但是每個方法的參數(主要是參數類型)不一樣,那么就稱這個方法有多個不同的版本,即方法重載,它是面向對象里多態屬性的一種表現。這些方法雖然同名,但是它們是不同的,因為函數真正的特征標識是它的參數,而不是函數名或返回類型。注意重載與前面的重寫的區別,重載是一個類里有多個不同版本的同名方法,重寫是子類覆蓋已定義在超類(即父類)的某個方法。

類參數

從前面的例子可以發現,多數時候類的列表參數僅僅是直接賦給某個字段。Scala為了進一步簡化代碼,允許在類參數前加上val或var來修飾,這樣就會在類的內部生成一個與參數同名的公有字段(此字段也是類的成員)。構造對象時,這些參數會直接復制給同名字段。除此之外,還可以加上關鍵字private、protected或override來表明字段的權限(關于權限修飾見后續章節)。如果參數沒有任何val或var關鍵字,那它就僅僅是“參數”,不是類的成員,只能用來初始化字段或給方法使用,外部不能訪問這樣的參數,內部也不能修改它,因為它不是類的成員。例如:

scala> class ab(a:Int){ //a不是類的成員,僅僅是個傳遞參數

?????| val b=a+1

?????| }

defined class ab

scala> val c=new ab(8)

c: ab = ab@6e2d3f2

scala> c.b

res0: Int = 9

scala> c.a

?????????^

???????error: value a is not a member of ab

以下在類參數定義時,加上val,則類參數同時變成了類成員:

scala> class ab(val a:Int){

?????| val b=a+1

?????| }

defined class ab

scala> val c=new ab(8)

c: ab = ab@ccd000e

scala> c.b

res2: Int = 9

scala> c.a

res3: Int = 8

單例對象與伴生對象

在Scala里,除了用new可以構造一個對象,也可以用“object”開頭定義一個對象。它類似于類的定義,只不過不能像類那樣有參數,也沒有構造方法。因此,不能用new來實例化一個object的定義,因為它已經是一個對象了,對比class用new可以實例化無數個對象,而object只能定義一個對象,因此也把object定義的對象叫單列對象,如果對于單列對象object A 存在伴生類class A,則又把object A叫Class A的伴生對象,它們可以相互訪問私有成員。概念雖多但是意思很明確d0c0a7c130b26c177aa7e039923854c2.png

工廠對象與工廠方法

如果定義一個方法專門用來構造某一個類的對象,那么這種方法就稱為“工廠方法”。包含這些工廠方法集合的單例對象,也就叫“工廠對象” 。通常,工廠方法會定義在伴生對象里。尤其是當一系列類存在繼承關系時,可以在基類的伴生對象里定義一系列對應的工廠方法。使用工廠方法的好處是可以不用直接使用new來實例化對象,改用方法調用,而且方法名可以是任意的,這樣對外隱藏了類的實現細節。例如:

? ? class Students(val name: String, var score: Int) {

??????def exam(s: Int) = score = s

??????override def toString = name + "'s score is " + score + "."

??????//?重寫超類方法toString,注意關鍵字override?

????}

????object Students {

???def registerStu(name: String, score: Int) = new Students(name, score)

????}

將文件students.scala編譯后,并在解釋器里用“import Students._”導入單例對象后,就能這樣使用:

????scala> import Students._

????import Students._

????scala> val stu = registerStu("Tim", 100)

????stu: Students = Tim's score is 100.

apply方法

類和伴生對象有一個特殊的方法名:apply,如果定義了這個方法,那么既可以顯式調用:“對象.apply(參數)” ,也可以隱式調用:“對象(參數)”。隱式調用時,編譯器會自動插入缺失的“.apply”。如果apply是無參方法,應該寫出空括號(這和普通方法不同),否則無法隱式調用。無論是類還是單例對象,都能定義這樣的apply方法。

通常,在伴生對象里定義名為apply的工廠方法,就能通過“伴生對象名(參數)”來構造一個對象。也常常在類里定義一個與類相關的、具有特定行為的apply方法,讓使用者可以隱式調用,進而隱藏相應的實現細節。例如:

class Students(val name: String, var score: Int) {

??????def apply(s: Int) = score = s

??????def display() = println("Current score is " + score + ".")

??????override def toString = name + "'s score is " + score + "."

????}

????object Students?{

??????def apply(name: String, score: Int) = new Students(name, score)

????}

? ? scala> val stu?= Students("laozhang", 59)?

? ??stu: Students?= laozhang's score is 59.

?//注意沒有使用new?Students("laozhang",?59),這是傳統構造方法

????scala> stu(60)

?? ?scala> stu.display

????Current score is 60.

其中“Students("laozhang", 59)”被翻譯成“Students.apply("laozhang", 59)”,也就是調用了伴生對象里的工廠方法,所以構造了一個Students的對象并賦給變量stu。“stu(60)”被翻譯成“stu.apply(60)” ,也就是更新了字段score的數據。

主函數

主函數是Scala程序唯一的入口,即程序是從主函數開始運行的。要提供這樣的入口,則必須在某個單例對象里定義一個名為“main”的函數,而且該函數只有一個參數,類型為字符串數組Array[String],函數的返回類型是Unit(即空類型,注意不是UInt類型哈)。任何符合條件的單例對象都能成為程序的入口。例如:

//在students.scala文件中定義

? ? class Students(val name: String, var score: Int) {

??????def apply(s: Int) = score = s

??????def display() = println("Current score is " + score + ".")

??????override def toString = name + "'s score is " + score + "."

????}

? ??object Students?{

??????def apply(name: String, score: Int) = new Students(name, score)

????}

//在?main.scala文件中定義

? ? object Start {

??????def main(args: Array[String]) = {

????????try {

??????????val score = args(1).toInt

??????????val s = Students(args(0), score)

??????????println(s.toString)

????????} catch {

? ? ? ? ? .....

????????} } }

使用命令“scalac students.scala main.scala”將兩個文件編譯后,就能用命令“scala Start 參數1 參數2”來運行程序。命令里的“Start”就是包含主函數main的單例對象的名字,后面可以輸入若干個用空格間隔的參數。這些參數被打包成字符串數組供主函數使用,也就是代碼里的args(0)、args(1)。

主函數的另外一種寫法是讓單例對象繼承“App”特質(特質的概念引入是因為scala不支持多重超類的繼承,為實現多重超類繼承的某些特性而引入了特質概念),這樣就只需在單例對象里編寫主函數的函數體,無需顯式定義main方法。例如:

? ? object Start?extends App {

??????try {

????????var sum = 0

????????for(arg

??????????sum += arg.toInt

????????}

????????println("sum = " + sum)

??????} catch {

? ? ? ? ......

??????}

????}

??將文件編譯后使用方法同前

關于class的知識,做為硬件設計語言chisel3/spinalHDL,這些已經夠用了。

照例結合spinalHDL給個小提示d0c0a7c130b26c177aa7e039923854c2.png

93cefbb4499cc3aa860df34e07294b58.png

以下視頻簡單演示伯克利分校的教學用riscv32處理器,其使用基于scala宿主語言的chisel3硬件設計語言編寫:

更多信息請長期關注微信公眾號:RiscV與IC設計

44b32c638be0efefc06d33491ac6aa38.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/258529.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258529.shtml
英文地址,請注明出處:http://en.pswp.cn/news/258529.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu下安裝FTP服務及使用(VSFTPD詳細設置)(二)

vsftpd 作為一個主打安全的FTP服務器,有很多的選項設置。下面介紹了vsftpd的配置文件列表,而所有的配置都是基于vsftpd.conf這個配置文件 的。本文將提供完整的vsftpd.conf的中文說明。學習本文的內容將有助于你初步了解vsftpd的配置文件,但針…

crontab命令

前一天學習了 at 命令是針對僅運行一次的任務,循環運行的例行性計劃任務,linux系統則是由 cron (crond) 這個系統服務來控制的。Linux 系統上面原本就有非常多的計劃性工作,因此這個系統服務是默認啟動的。另外, 由于使用者自己也可以設置計劃…

調查顯示企業對 Linux 開發人才需求日漸增長

根據2014年Linux就業報告調查顯示,隨著Linux平臺增長,Linux平臺開發者就業需求較去年提升了7%,技術公司招聘Linux開發經歷的人才需求達到 77%,這是來自Dice和Linux基金會共同對就業市場對Linux人才的全景式調查,調查訪…

求圓和橢圓上任意角度的點的坐標

圓上任意角度的點的坐標 如上圖,給定圓心(Cx,Cy),半徑為R, 求θ\thetaθ對應的點的坐標? 此處θ\thetaθ是相對于水平軸的角度。 顯然我們可以使用極坐標轉換來求: {pxCxRcos(θ)pyCyRsin(θ)\left\{\begi…

BZOJ ac100題存檔

不知不覺AC100題了,放眼望去好像都是水題。在這里就做一個存檔吧(特別感謝各位大神尤其是云神http://hi.baidu.com/greencloud和麗潔姐http://wjmzbmr.com/的blog提供的題解) 代碼什么的有時間在放。 1000: AB Problem 好吧,這也算…

Android Build.VERSION.SDK_INT兼容介紹

盡管Android向下兼容不好,但是一個程序還是可以在多個平臺上跑的。向下兼容不好,接口改變,新的平臺上不能用舊的API,舊的平臺更不可能用新的API,不等于一個平臺需要一個APK。可以在高SDK上開發,并在程序中作…

smtp中mailfrom是必須的嗎_你是住在高層建筑中嗎?這是你必須了解的

01PARTONE消防電梯和普通客梯的作用及特點1.消防電梯是在建筑物發生火災時供消防人員進行滅火與救援使用且具有一定功能的電梯。因此,消防電梯具有較高的防火要求,其防火設計十分重要。2.普通電梯均不具備消防功能,發生火災時禁止人們搭乘電梯…

c++ 函數的值傳遞,引用傳遞 和 引用返回的探索

2019獨角獸企業重金招聘Python工程師標準>>> 前言 C的函數參數和返回分為按值傳遞和按引用傳遞,應用到類上面,會涉及到類的 賦值操作 復制函數 構造函數 析構函數 雖然java開發了兩年,但對我而言c我還只是一個初學者.c還有很多陌生的特性需要自己親自探索.這里用實際…

GCD的部分總結

GCD是基于C語言的底層API,用Block定義任務用起來非常靈活便捷. GCD的基本思想是就將操作放在隊列中去執行 (1)操作使用Blocks定義(2)隊列負責調度任務執行所在的線程以及具體的執行時間(3)隊列的特點是先進先出(FIFO)的,新添加至對列的操作都會排在隊尾關于多線程的…

將bgr彩色矩陣歸一化到0-255之間 【RGB image normalization】

參考下面文章,可以使用normalize 函數。 https://blog.csdn.net/kuweicai/article/details/78988886 對于彩色rgb圖像,也可以直接使用以上函數, 參考 https://devtalk.nvidia.com/default/topic/1042100/rgb-image-normalization/?offset8 image cv2…

多線程編程2-NSOperation

本文目錄 前言一、NSInvocationOperation二、NSBlockOperation三、NSOperation的其他用法四、自定義NSOperation回到頂部前言 1.上一講簡單介紹了NSThread的使用,雖然也可以實現多線程編程,但是需要我們去管理線程的生命周期,還要考慮線程同步…

python圖片顯示英文字符_python如何解析字符串中出現的英文人名?

這里有四個例子,結果來自google scholarstr1 "Jakes, William C., and Donald C. Cox. Microwave mobile communications. Wiley-IEEE Press, 1994."str2 "Schlegel, David J., Douglas P. Finkbeiner, and Marc Davis. \"Maps of dust infra…

閃回表操作語法+使用閃回刪除

閃回表操作語法 flashback table 【 schema.】 table_name to {【before drop 【rename to new_table_name】 】|【scn | timestamp 】】 expr 【enable | disable 】 triggers}: 參數說明: schema:用戶模式 before drop:表示恢復到刪除…

在現有的python環境下創建另一個python版本【親測有效】

比如,你現在的python環境是3.6,想要使用一個3.5,可以在anaconda環境下使用conda虛擬環境。 第一步: conda create -n py35 【創建Py35虛擬環境】 第二步: 進入環境 activate py35 第三步: 升級或者降…

時間戳

我發現,我在本站公布的文章,url 最后一段都是 134 開頭的一串數字。一開始并沒在意,僅僅想當然以為是程序隨機生成的。 昨天跟程序作者交談的過程中無意問起,他說這是代表時間的。剛才訪問 GoAgent 項目時發現,其作者 …

歐拉函數 - HDU1286

歐拉函數的作用: 有[1,2.....n]這樣一個集合,f(n)這個集合中與n互質的元素的個數。歐拉函數描述了一些列與這個f(n)有關的一些性質,如下: 1、令p為一個素數,n p ^ k,則 f(n) p ^ k - p ^ (k-1) 2、令m&…

其中一個頁簽慢_渭南提升一個大專學歷的有效方法

渭南提升一個大專學歷的有效方法,宏德教育,目前已形成以高等學歷教育為特色王牌,職稱考評、企業內訓為輔助的強力優勢品牌。渭南提升一個大專學歷的有效方法, 獲得發明專利或實用新型專利,且已實施取得效益。出版本專業…

《收集蘋果》 動態規劃入門

問題描寫敘述 平面上有N*M個格子,每一個格子中放著一定數量的蘋果。你從左上角的格子開始,每一步僅僅能向下走或是向右走,每次走到一個格子上就把格子里的蘋果收集起來,這樣下去,你最多能收集到多少個蘋果。 輸入&…

Xamarin XAML語言教程通過ProgressTo方法對進度條設置

2019獨角獸企業重金招聘Python工程師標準>>> Xamarin XAML語言教程通過ProgressTo方法對進度條設置 在ProgressBar中定義了一個ProgressTo方法,此方法也可以用來對進度條當前的進行進行設置,ProgressTo與Progress屬性的不同之處在于ProgressT…

Radar Installation

題目鏈接:http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id27586 題意: 在海岸線上擺放雷達并限定雷達覆蓋半徑d,再以海岸線為軸,給定海上島嶼坐標,求至少需要多少雷達可以覆蓋所以島嶼,如…