實驗二Scala 語言基礎
實驗一是對於linux系統的安裝和常用命令,在之前的博客園隨筆中已經有了記錄,所以便不再贅述,直接開始第二章關於scala語言的學習
對於scala語言,今天並沒有完全學習完,只是完成了實驗內容,在下面會總結一下,自己在完成實驗過程中的總結的幾個剛接觸的易錯點
1. 計算級數
請用腳本的方式編程計算並輸出下列級數的前n項之和Sn,直到Sn剛好大於或等於q 為止,其中q為大於0的整數,其值通過鍵盤輸入。sn=2/1+3/2+4/3+…n+1/n,例如,若 q 的值為 50.0,則輸出應為:Sn=50.416695。請將源文件保存為exercise2-1.scala,在REPL模式下測試運行,測試樣例:q=1時,Sn=2;q=30時,Sn=30.891459; q=50時,Sn=50.416695。
object demo { def main(args: Array[String]): Unit = { import scala.io.StdIn println("請輸入Q值:") val number = StdIn.readDouble() var sn=0.toDouble var i = 0.toDouble while (number > sn ){ i=i+1 val temp = ((i + 1) / i).toDouble println(temp) sn=sn+((i+1)/i) } println(number) println(sn) } }
注意點:對於sn和i值都需要進行toDouble方法轉換,否則默認的是int類型,所以在剛運行的時候,每次都是會+1,輸出的一直都是50,后來找到原因在這里。
2. 模擬圖形繪制
對於一個圖形繪制程序,用下面的層次對各種實體進行抽象。定義一個Drawable的特質,其包括一個draw方法,默認實現為輸出對象的字符串表示。定義一個Point類表示點,其混入了Drawable特質,並包含一個shift方法,用於移動點。所有圖形實體的抽象類為 Shape,其構造函數包括一個Point類型,表示圖形的具體位置(具體意義對不同的具體圖形不一樣)。Shape類有一個具體方法moveTo和一個抽象方法zoom,其中moveTo將圖形從當前位置移動到新的位置, 各種具體圖形的moveTo可能會有不一樣的地方。zoom方法實現對圖形的放縮,接受一個浮點型的放縮倍數參數,不同具體圖形放縮實現不一樣。繼承Shape類的具體圖形類型包括直線類Line和圓類Circle。Line類的第一個參數表示其位置,第二個參數表示另一個端點,Line放縮的時候,其中點位置不變,長度按倍數放縮(注意,縮放時,其兩個端點信息也改變了),另外,Line的move行為影響了另一個端點,需要對 move方法進行重載。Circle類第一個參數表示其圓心,也是其位置,另一個參數表示其半徑,Circle縮放的時候,位置參數不變,半徑按倍數縮放。另外直線類Line和圓類Circle 都混入了Drawable特質,要求對draw進行重載實現,其中類Line的draw輸出的信息樣式為“Line:第一個端點的坐標--第二個端點的坐標)”,類Circle的draw輸出的信息樣式為“Circle center:圓心坐標,R=半徑”。如下的代碼已經給出了Drawable和Point的定義,同時也給出了程序入口main函數的實現,請完成Shape類、Line類和Circle類的定義。
case class Point(var x: Double, var y: Double) extends Drawable { var Px: Double = x var Py: Double = y def shift(deltaX: Double, deltaY: Double) { Px += deltaX Py += deltaY } override def draw(): Unit = { println("Point:(" + Px + "," + Py + ")") } } trait Drawable { def draw() { println(this.toString) } } abstract class Shape extends Drawable { def moveTo(point: Point) def zoom(step: Double) def draw() } class Line(point1: Point, point2: Point) extends Shape { override def moveTo(point: Point): Unit = { point1.shift(point.Px, point.Py) point2.shift(point.Px, point.Py) } override def zoom(step: Double): Unit = { var tempx = (point2.Px + point1.Px) / 2 - point1.Px if (tempx < 0) { tempx = 0 - tempx } var centerx = ((point2.Px + point1.Px) / 2) var zoomlengthx = (tempx * step) point1.Px = centerx - zoomlengthx point2.Px = centerx + zoomlengthx var tempy = (point2.Py + point1.Py) / 2 - point1.Py if (tempy < 0) { tempy = 0 - tempy } var centery = ((point2.Py + point1.Py) / 2) var zoomlengthy = (tempy * step) point1.Py = centery - zoomlengthy point2.Py = centery + zoomlengthy } override def draw(): Unit = { println("Line:(" + point1.Px + "," + point1.Py + ")--(" + point2.Px + "," + point2.Py + ")") } } class Circle(point: Point, r: Double) extends Shape { var R=r override def moveTo(point: Point): Unit = { this.point.Px=point.Px this.point.Py=point.Py } override def zoom(step: Double): Unit = { R=R*step } override def draw(): Unit = { println("Circle center:(" + point.Px + "," + point.Py + "),R=" + R) } } object demo2 { def main(args: Array[String]) { val p = new Point(10, 30) p.draw; val line1 = new Line(Point(0, 0), Point(20, 20)) line1.draw line1.moveTo(Point(5, 5)) //移動到一個新的點 line1.draw line1.zoom(2) //放大兩倍 line1.draw val cir = new Circle(Point(10, 10), 5) cir.draw cir.moveTo(Point(30,20)) cir.draw cir.zoom(0.5) cir.draw } }
注意點:第二個實驗內容考察的是對於scala中繼承的一些注意點,就是在構造方法上有一些區別,同時需要注意的是var是代表該變量是可以被重新賦值的,而val則是不可以被重新賦值的,這個需要注意,但是val的好處就是易於被回收。在scala中,類默認的變量類型是可以被其他類訪問的類型(可以認為是public類型),如果加上private就是無法訪問,但是scala又特殊在有一個伴生類的東西,即單例對象與類同名時,這個單例對象被稱為這個類的伴生對象,而這個類被稱為這個單例對象的伴生類。伴生類和伴生對象要在同一個源文件中定義,伴生對象和伴生類可以互相訪問其私有成員。還有就是在構造函數的時候,出了構造函數意外的方法是不會被調用的,其他的語句都是會被執行的,這個與其他語言不同。
3.統計學生信息
學生的成績清單格式如下所示,第一行為表頭,各字段意思分別為學號、性別、課程名
課程名2等,后面每一行代表一個學生的信息,各字段之間用空白符隔開
Id gender Math English Physics
301610 male 80 64 78
301611 female 65 87 58
...
給定任何一個如上格式的清單(不同清單里課程數量可能不一樣),要求盡可能采用函數式編程,統計出各門課程的平均成績,最低成績,和最高成績;另外還需按男女同學分開,分別統計各門課程的平均成績,最低成績,和最高成績。
import scala.collection.mutable.ArrayBuffer class Student(id: Int, gender: String, math: Int, english: Int, physics: Int) { var SiD = id var Sgender = gender var Smath = math var Senglish = english var Sphysics = physics } object demo3 { def main(args: Array[String]): Unit = { var studentlist = new ArrayBuffer[Student]() studentlist.append(new Student(301610, "male", 80, 64, 78)) studentlist.append(new Student(301611, "female", 65, 87, 58)) studentlist.append(new Student(301612, "female", 44, 71, 77)) studentlist.append(new Student(301613, "female", 66, 71, 91)) studentlist.append(new Student(301614, "female", 70, 71, 100)) studentlist.append(new Student(301615, "male", 72, 77, 72)) studentlist.append(new Student(301616, "female", 73, 81, 75)) studentlist.append(new Student(301617, "female", 69, 77, 75)) studentlist.append(new Student(301618, "male", 73, 61, 65)) studentlist.append(new Student(301619, "male", 74, 69, 68)) studentlist.append(new Student(301620, "male", 76, 62, 76)) studentlist.append(new Student(301621, "male", 73, 69, 91)) studentlist.append(new Student(301622, "male", 55, 69, 61)) studentlist.append(new Student(301623, "male", 50, 58, 75)) studentlist.append(new Student(301624, "female", 63, 83, 93)) studentlist.append(new Student(301625, "male", 72, 54, 100)) studentlist.append(new Student(301626, "male", 76, 66, 73)) studentlist.append(new Student(301627, "male", 82, 87, 79)) studentlist.append(new Student(301628, "female", 62, 80, 54)) studentlist.append(new Student(301629, "male", 89, 77, 72)) sortsum(studentlist) } def sortsum(list: ArrayBuffer[Student]): Unit = { var count=0 var mathSum = 0 var mathAverage = 0 var mathMin = 100 var mathMax = 0 var englishSum = 0 var englishAverage = 0 var englishMin = 100 var englishMax = 0 var physicsSum = 0 var physicsAverage = 0 var physicsMin = 100 var physicsMax = 0 var femaleSrudent=new ArrayBuffer[Student]() var maleSrudent=new ArrayBuffer[Student]() list.foreach(student => { count+=1 if(student.Sgender.equals("female")){ femaleSrudent.append(student) }else{ maleSrudent.append(student) } if(student.Smath>mathMax){ mathMax=student.Smath }else if(student.Smath<mathMin){ mathMin=student.Smath } if(student.Senglish>englishMax){ englishMax=student.Senglish }else if(student.Senglish<englishMin){ englishMin=student.Senglish } if(student.Sphysics>physicsMax){ physicsMax=student.Sphysics }else if(student.Sphysics<physicsMin){ physicsMin=student.Sphysics } mathSum+=student.Smath englishSum+=student.Senglish physicsSum+=student.Sphysics }) mathAverage=mathSum/count englishAverage=englishSum/count physicsAverage=physicsSum/count println("course\t\taverage\tmin\tmax") println("Math:\t\t"+mathAverage+"\t\t"+mathMin+"\t"+mathMax) println("English:\t"+englishAverage+"\t\t"+englishMin+"\t"+englishMax) println("Physics:\t"+physicsAverage+"\t\t"+physicsMin+"\t"+physicsMax) sortmale(maleSrudent) sortfemale(femaleSrudent) } def sortmale(list: ArrayBuffer[Student]): Unit = { var count=0 var mathSum = 0 var mathAverage = 0 var mathMin = 100 var mathMax = 0 var englishSum = 0 var englishAverage = 0 var englishMin = 100 var englishMax = 0 var physicsSum = 0 var physicsAverage = 0 var physicsMin = 100 var physicsMax = 0 list.foreach(student => { count+=1 if(student.Smath>mathMax){ mathMax=student.Smath }else if(student.Smath<mathMin){ mathMin=student.Smath } if(student.Senglish>englishMax){ englishMax=student.Senglish }else if(student.Senglish<englishMin){ englishMin=student.Senglish } if(student.Sphysics>physicsMax){ physicsMax=student.Sphysics }else if(student.Sphysics<physicsMin){ physicsMin=student.Sphysics } mathSum+=student.Smath englishSum+=student.Senglish physicsSum+=student.Sphysics }) mathAverage=mathSum/count englishAverage=englishSum/count physicsAverage=physicsSum/count println("course\t\taverage\tmin\tmax(males)") println("Math:\t\t"+mathAverage+"\t\t"+mathMin+"\t"+mathMax) println("English:\t"+englishAverage+"\t\t"+englishMin+"\t"+englishMax) println("Physics:\t"+physicsAverage+"\t\t"+physicsMin+"\t"+physicsMax) } def sortfemale(list:ArrayBuffer[Student]): Unit = { var count=0 var mathSum = 0 var mathAverage = 0 var mathMin = 100 var mathMax = 0 var englishSum = 0 var englishAverage = 0 var englishMin = 100 var englishMax = 0 var physicsSum = 0 var physicsAverage = 0 var physicsMin = 100 var physicsMax = 0 list.foreach(student => { count+=1 if(student.Smath>mathMax){ mathMax=student.Smath }else if(student.Smath<mathMin){ mathMin=student.Smath } if(student.Senglish>englishMax){ englishMax=student.Senglish }else if(student.Senglish<englishMin){ englishMin=student.Senglish } if(student.Sphysics>physicsMax){ physicsMax=student.Sphysics }else if(student.Sphysics<physicsMin){ physicsMin=student.Sphysics } mathSum+=student.Smath englishSum+=student.Senglish physicsSum+=student.Sphysics }) mathAverage=mathSum/count englishAverage=englishSum/count physicsAverage=physicsSum/count println("course\t\taverage\tmin\tmax(females)") println("Math:\t\t"+mathAverage+"\t\t"+mathMin+"\t"+mathMax) println("English:\t"+englishAverage+"\t\t"+englishMin+"\t"+englishMax) println("Physics:\t"+physicsAverage+"\t\t"+physicsMin+"\t"+physicsMax) } }
注意點:這里面需要注意的是Array類型的使用,其他方面的話只有一點,那就是構造函數的重載,
class Student(id: Int, gender: String, math: Int, english: Int, physics: Int) { var SiD = id var Sgender = gender var Smath = math var Senglish = english var Sphysics = physics def this(id: Int, gender: String, math: Int, english: Int, physics: Int,science:Int ){ this(id: Int, gender: String, math: Int, english: Int, physics: Int) var Sscience=science } }
可以看出如果對這個類構造函數重載的時候,需要寫def this方法,並在第一句中加上第一個構造方法。