成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Scala代碼編寫中常見的十大陷阱

原創(chuàng)
開發(fā) 后端
很多Java開發(fā)者在學(xué)習(xí)Scala語言的時(shí)候,往往覺得Scala的語法和用法有些過于復(fù)雜,充滿語法糖,太“甜”了。在使用Scala編寫代碼時(shí),由于語法和編寫習(xí)慣的不同,很多開發(fā)者會(huì)犯相同或相似的錯(cuò)誤。一位Scala狂熱愛好者近日總結(jié)了十大這樣的錯(cuò)誤,以供參考。

【51CTO精選譯文】對(duì)于支持并發(fā)和分布式處理、高可擴(kuò)展、基于組件的應(yīng)用程序來說,Scala的功能是很強(qiáng)大的。它利用了面向?qū)ο蠛秃瘮?shù)式程序設(shè)計(jì)的優(yōu)點(diǎn)。這種基于Java虛擬機(jī)的語言在宣布Twitter正使用它時(shí)受到了最多的沖擊(相關(guān)51CTO評(píng)論:從Scala進(jìn)駐Twitter看多語言混雜系統(tǒng)的前景)。如果使用正確,Scala可以大量減少應(yīng)用程序?qū)Υa的需求。

對(duì)于Scala編程, 我們收集了這些常見代碼編寫中的陷阱。這些技巧來自于Daniel Sobral,一個(gè)曾參加過FreeBSD項(xiàng)目和Java軟件開發(fā)工程的Scala狂熱愛好者。

1. 語法錯(cuò)誤

認(rèn)為  “yield” 像 ”return” 一樣。有人會(huì)這樣寫:

  1. for(i <- 0 to 10) {  
  2.   if (i % 2 == 0)  
  3.     yield i  
  4.   else 
  5.     yield -i  

正確的表示應(yīng)該是:

  1. for(i <- 0 to 10)   
  2. yield {  
  3.   if (i % 2 == 0)  
  4.     i  
  5.   else 
  6.     -i  

2. 誤用和語法錯(cuò)誤

濫用scala.xml.XML.loadXXX。這個(gè)的語法分析器試圖訪問外部的DTD、strip組件或類似的東西。在scala.xml.parsing.ConstructingParser.fromXXX中有另一個(gè)可選的語法分析器。同時(shí),在處理XML時(shí)忘記了等號(hào)兩端的空格。比如:

  1. val xml=<root/> 

這段代碼真正的意思是:

  1. val xml.$equal$less(root).$slash$greater  
  2.   

這種情況的發(fā)生是由于操作符相當(dāng)隨意,而且scala采用這樣一種事實(shí):字母數(shù)字字符與非字母數(shù)字字符通過下劃線可以結(jié)合成為一個(gè)有效的標(biāo)識(shí)符。這也使得“x+y”這樣的表達(dá)式不會(huì)被當(dāng)成一個(gè)標(biāo)識(shí)符。而應(yīng)該注意 “x_+”是一個(gè)有效的標(biāo)識(shí)符。所以,賦值標(biāo)識(shí)符的寫法應(yīng)該是:

  1. val xml = <root/> 

3. 用法錯(cuò)誤

為那些根本不是無關(guān)緊要的應(yīng)用加入Application特征。

  1. object MyScalaApp extends Application {    
  2.   // ... body ...  

#t#示例部分的問題在于,body部分在單元對(duì)象初始化時(shí)執(zhí)行。首先,單元初始化的執(zhí)行是異步的,因此你的整個(gè)程序不能與其它線程交互;其次,即時(shí)編譯器(JIT)不會(huì)優(yōu)化它,因此你的程序速度慢下來,這是沒有必要的。

另外,不能與其它線程的交互也意味著你會(huì)忘記測(cè)試應(yīng)用程序的GUI或者Actors。

4. 用法錯(cuò)誤

試圖模式匹配一個(gè)字符串的正則表達(dá)式,而又假定該正則表達(dá)式是無界的:

  1. val r = """(\d+)""".r  
  2. val s = "--> 5 <---" 
  3. s match {  
  4.   case r(n) => println("This won't match")  
  5.   case _ => println("This will")  

此處的問題在于, 當(dāng)模式模式匹配時(shí), Scala的正則表達(dá)式表現(xiàn)為如同開始于”^”,結(jié)束于”$”。使之工作的正確寫法是:

  1. val r = """(\d+)""".r  
  2. val s = "--> 5 <---" 
  3. r findFirstIn s match {  
  4.   case Some(n) => println("Matches 5 to "+n)  
  5.   case _ => println("Won't match")  

或者確保模式能匹配任意前綴和后綴:

  1. val r = """.*(\d+).*""".r  
  2. val s = "--> 5 <---" 
  3. s match {  
  4.   case r(n) => println("This will match the first group of r, "+n+", to 5")  
  5.   case _ => println("Won't match")  

#p#

5. 用法錯(cuò)誤

把var和val認(rèn)為是字段(fields):

Scala強(qiáng)制使用統(tǒng)一訪問準(zhǔn)則(Uniform Access Principle),這使得我們無法直接引用一個(gè)字段。所有對(duì)任意字段的訪問只能通過getters和setters。val和var事實(shí)上只是定義一個(gè)字段,getter作為val字段,對(duì)于var則定義一個(gè)setter。

#t#Java程序員通常認(rèn)為var和val是字段,而當(dāng)發(fā)現(xiàn)在他們的方法中它們共享相同的命名空間時(shí),常常覺得驚訝。因此,不能重復(fù)使用它們的名字。共享命名空間的是自動(dòng)定義的getter和setter而不是字段本身。通常程序員們會(huì)試圖尋找一種訪問字段的方法,從而可以繞過限制——但這只是徒勞,統(tǒng)一訪問準(zhǔn)則是無法違背的。它的另一個(gè)后果是,當(dāng)進(jìn)行子類化時(shí)val會(huì)覆蓋def。其它方法是行不通的,因?yàn)関al增加了不變性保證,而def沒有。

當(dāng)你需要重載時(shí),沒有任何準(zhǔn)則會(huì)指導(dǎo)你如何使用私有的getters和setters。Scala編譯器和庫代碼常使用私有值的別名和縮寫,反之公有的getters和setters則使用fullyCamelNamingConventions(一種命名規(guī)范)。其它的建議包括:重命名、實(shí)例中的單元化,甚至子類化。這些建議的例子如下:

重命名

  1. class User(val name: String, initialPassword: String) {  
  2.   private lazy var encryptedPassword = encrypt(initialPassword, salt)  
  3.   private lazy var salt = scala.util.Random.nextInt  
  4.  
  5.   private def encrypt(plainText: String, salt: Int): String = { ... }  
  6.   private def decrypt(encryptedText: String, salt: Int): String = { ... }  
  7.  
  8.   def password = decrypt(encryptedPassword, salt)  
  9.   def password_=(newPassword: String) = encrypt(newPassword, salt)  

單例模式(Singleton)

  1. class User(initialName: String, initialPassword: String) {  
  2.    private object fields {  
  3.      var name: String = initialName;  
  4.      var password: String = initialPassword;  
  5.    }  
  6.    def name = fields.name  
  7.    def name_=(newName: String) = fields.name = newName  
  8.    def password = fields.password  
  9.    def password_=(newPassword: String) = fields.password = newPassword  
  10.  } 

或者,對(duì)于一個(gè)類來說,可以為相等關(guān)系或hashCode自動(dòng)定義可被重用的方法

  1. class User(name0: String, password0: String) {  
  2.   private case class Fields(var name: String, var password0: String)  
  3.   private object fields extends Fields(name0, password0)  
  4.  
  5.  
  6.   def name = fields.name  
  7.   def name_=(newName: String) = fields.name = newName  
  8.   def password = fields.password  
  9.   def password_=(newPassword: String) = fields.password = newPassword  

子類化

  1. case class Customer(name: String)  
  2.  
  3. class ValidatingCustomer(name0: String) extends Customer(name0) {  
  4.   require(name0.length < 5)  
  5.  
  6.   def name_=(newName : String) =  
  7.     if (newName.length < 5) error("too short")  
  8.     else super.name_=(newName)  
  9. }  
  10.  
  11. val cust = new ValidatingCustomer("xyz123"

6. 用法錯(cuò)誤

忘記類型擦除(type erasure)。當(dāng)你聲明了一個(gè)類C[A]、一個(gè)泛型T[A]或者一個(gè)函數(shù)或者方法m[A]后,A在運(yùn)行時(shí)并不存在。這意味著,對(duì)于實(shí)例來講,任何參數(shù)都將被編譯成AnyRef,即使編譯器能夠保證在編譯過程中類型不會(huì)被忽略掉。

這也意味著在編譯時(shí)你不能使用類型參數(shù)A。例如,下面這些代碼將不會(huì)工作:

  1. def checkList[A](l: List[A]) = l match {  
  2.   case _ : List[Int] => println("List of Ints")  
  3.   case _ : List[String] => println("List of Strings")  
  4.   case _ => println("Something else")  

在運(yùn)行時(shí),被傳遞的List沒有類型參數(shù)。 而List[Int]和List[String]都將會(huì)變成List[_]. 因此只有第一種情況會(huì)被調(diào)用。

你也可以在一定范圍內(nèi)不使用這種方法,而采用實(shí)驗(yàn)性的特性Manifest, 像這樣:

  1. def checkList[A](l: List[A])(implicit m: scala.reflect.Manifest[A]) = m.toString match {  
  2.   case "int" => println("List of Ints")  
  3.   case "java.lang.String" => println("List of Strings")  
  4.   case _ => println("Something else")  

#p#

7. 設(shè)計(jì)錯(cuò)誤

Implicit關(guān)鍵字的使用不小心。Implicits非常強(qiáng)大,但要小心,普通類型不能使用隱式參數(shù)或者進(jìn)行隱匿轉(zhuǎn)換。

例如,下面一個(gè)implicit表達(dá)式:

  1. implicit def string2Int(s: String): Int = s.toInt 

這是一個(gè)不好的做法,因?yàn)橛腥丝赡苠e(cuò)誤的使用了一個(gè)字符串來代替Int。對(duì)于上面的這種情況,更好的方法是使用一個(gè)類。

  1. case class Age(n: Int)  
  2. implicit def string2Age(s: String) = Age(s.toInt)  
  3. implicit def int2Age(n: Int) = new Age(n)  
  4. implicit def age2Int(a: Age) = a.n 

這將會(huì)使你很自由的將Age與String或者Int結(jié)合起來,而不是讓String和Int結(jié)合。類似的,當(dāng)使用隱式參數(shù)時(shí),不要像這樣做:

  1. case class Person(name: String)(implicit age: Int) 

這不僅因?yàn)樗菀自陔[式參數(shù)間產(chǎn)生沖突,而且可能導(dǎo)致在毫無提示情況下傳遞一個(gè)隱式的age, 而接收者需要的只是隱式的Int或者其它類型。同樣,解決辦法是使用一個(gè)特定的類。

另一種可能導(dǎo)致implicit用法出問題的情況是有偏好的使用操作符。你可能認(rèn)為”~”是字符串匹配時(shí)最好的操作符,而其他人可能會(huì)使用矩陣等價(jià)(matrix equivalence),分析器連接等(符號(hào))。因此,如果你使用它們,請(qǐng)確保你能夠很容易的分離其作用域。

8. 設(shè)計(jì)錯(cuò)誤

設(shè)計(jì)不佳的等價(jià)方法。尤其是:

◆試著使用“==”代替“equals”(這讓你可以使用“!=”)

◆使用這樣的定義:

  1. def equals(other: MyClass): Boolean 

而不是這樣的:

  1. override def equals(other: Any): Boolean  
  2.   

◆忘記重載hashCode,以確保當(dāng)a==b時(shí)a.hashCode==b.hashCode(反之不一定成立)。

◆不可以這樣做交換: if a==b then b==a。特別地,當(dāng)考慮子類化時(shí),超類是否知道如何與一個(gè)子類進(jìn)行對(duì)比,即使它不知道該子類是否存在。如果需要請(qǐng)查看canEquals的用法。

◆不可以這樣做傳遞: if a==b and b ==c then a==c。

9. 用法錯(cuò)誤

在Unix/Linux/*BSD的系統(tǒng)中,對(duì)你的主機(jī)進(jìn)行了命名卻沒有在主機(jī)文件中聲明。特別的,下面這條指令不會(huì)工作:

  1. ping `hostname`  
  2.   

#t#在這種情況下,fsc和scala都不會(huì)工作,而scalac則可以。這是因?yàn)閒sc運(yùn)行在背景模式下,通過TCP套接字監(jiān)聽連接來加速編譯,而scala卻用它來加快腳本的執(zhí)行速度。

10.風(fēng)格錯(cuò)誤

使用while。雖然它有自己的用處,但大多數(shù)時(shí)候使用for往往更好。在談到for時(shí),用它們來產(chǎn)生索引不是一個(gè)好的做法。

避免這樣的使用:

  1. def matchingChars(string: String, characters: String) = {  
  2.   var m = "" 
  3.   for(i <- 0 until string.length)  
  4.     if ((characters contains string(i)) && !(m contains string(i)))  
  5.       m += string(i)  
  6.   m  

而應(yīng)該使用:

  1. def matchingChars(string: String, characters: String) = {  
  2.   var m = "" 
  3.   for(c <- string)  
  4.     if ((characters contains c) && !(m contains c))  
  5.       m += c  
  6.   m  

如果有人需要返回一個(gè)索引,可以使用下面的形式來代替按索引迭代的方法。如果對(duì)性能有要求,它可以較好的應(yīng)用在投影(projection)(Scala 2.7)和視圖(Scala 2.8)中。

  1. def indicesOf(s: String, c: Char) = for {  
  2.   (sc, index) <- s.zipWithIndex  
  3.   if c == sc  
  4. } yield index   

【51CTO.com譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com,且不得修改原文內(nèi)容。】

原文:10 Scala Programming Pitfalls  作者:mitchp

責(zé)任編輯:yangsai 來源: 51CTO.com
相關(guān)推薦

2024-08-16 21:38:43

Python代碼編程

2013-10-23 14:34:15

2010-08-16 13:51:22

DIV+CSS

2015-06-08 13:51:56

WiFi

2013-04-27 17:09:29

安全管理IT技術(shù)

2010-10-26 10:16:36

求職

2011-06-07 15:34:15

2020-08-13 06:43:41

React前端開發(fā)

2014-02-14 16:23:03

移動(dòng)互聯(lián)網(wǎng)系統(tǒng)架構(gòu)

2014-02-13 11:06:52

系統(tǒng)架構(gòu)移動(dòng)互聯(lián)網(wǎng)

2023-06-08 00:16:58

2010-08-18 13:13:04

CSS兼容性IE6

2010-08-26 08:55:08

IE6CSS兼容性

2024-03-04 13:23:00

數(shù)字化轉(zhuǎn)型

2015-02-05 08:48:07

云遷移云資源管理

2018-10-31 08:55:02

2009-07-21 10:04:57

Scala編程語言

2011-04-29 10:37:01

CRM

2025-01-06 00:02:51

2020-03-16 09:00:00

Linux郵件客戶端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 久久精品视频99 | 国产精品99999999 | 91在线观看免费视频 | 国产精品国产精品国产专区不片 | 久久久久久成人 | 国产精品美女久久久久aⅴ国产馆 | 国产精品免费福利 | 国产精品中文在线 | 国产精品成人国产乱 | 97伦理电影 | 亚洲一区不卡在线 | 四虎成人免费电影 | 91视频网址 | 精品福利av导航 | 久久视频精品 | 国产1区2区在线观看 | 日韩在线91 | 欧美激情综合五月色丁香小说 | 精品视频一区二区 | 成人一区二区在线 | 天天操网 | 懂色中文一区二区三区在线视频 | 青青草一区 | 欧美一区视频 | 欧美一区二区三区在线观看视频 | 国产一区二区三区在线 | 四虎成人精品永久免费av九九 | 欧美激情在线一区二区三区 | 综合二区 | 亚洲精品久久久久久一区二区 | 成人精品一区二区三区中文字幕 | 日韩在线中文字幕 | 成人深夜福利 | 久久久久久久久久久久一区二区 | 久久久精品视频一区二区三区 | 伊人色综合久久天天五月婷 | 51ⅴ精品国产91久久久久久 | 韩日一区二区 | 国产自产21区 | 91久久国产综合久久 | 成人h动漫精品一区二区器材 |