你見過哪些令你瞠目結舌的 Scala 代碼技巧?
好吧,耐不住也來湊個熱鬧
瞠目結舌 這種事情一般發生在初學者身上,因為瞠著瞠著你就習慣了,這個時候更容易發生的事情是再去看以前寫的Java/C代碼感覺:這代碼寫的真TMD的好啰嗦啊。
既然回答了,我就貼個我覺得很有意思的代碼吧:(僅使用標準API)一行代碼實現斐波拉契數列。當然如果使用像shapeless、Scalaz之類的庫可以寫出很多有趣的代碼。
scala&> val fibs: Stream[Int] = 0 #:: fibs.scanLeft(1){ _+_ }
fibs: Stream[Int] = Stream(0, ?)
scala&> fibs take 10 toList
res0: List[Int] = List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
type level coding = compilable documentation.
概念上還是老祖宗那邊過來的,這個網址有不少栗子,不用翻牆的
Type-Level Programming in ScalaType-Level programming的目的就是通過一些複合性類型限定,使得Scala的程序既能提供一些弱類型系統裡面好玩的靈活性,又要保持強類型系統裡面讓編譯器能進行的校驗,加上必須顯式的類型宣告和隱式的類型引用,使得在代碼能直接清晰地告訴你,什麼行的通,什麼行不通。以及,減少boilerplate.
原則上來說,是因為以下的一些工具
implicitly[T] 和 T =:= T,B &<:&< T, A &<%&< T這裡的implicit因為一般會做Type check和要求提供T裡面相應的implicit value 而 T可以是各種複雜的類型表達,因為type-level的抽象度比較高,這些類型校驗是在編譯時候進行的,使得一些type class 編寫更有針對性。
---插一句,老祖宗的表達方式不一樣,目的還是一致的。
不謝邀,嚴格意義上來說我不能算是一個Geek,因為我對花哨的編程技巧不感興趣,我關注的是在工程上能否真正具有價值。即使我之前花時間研究一些優雅的實現和漂亮的代碼技巧,目的也只是為了在工程中能夠高效且能解決實際問題。所以我從不和人爭論語言的優劣,也很少在設計上由於主觀原因對一些技術進行選擇。
如果對某個語言都足夠熟悉且大家水平都近似的情況下,我在項目里寫了一段令同事「瞠目結舌」的代碼,我認為這是我工作的失敗,因為我的代碼是令人一看之下難以理解的。這並不是一個褒義詞。
所以,我認為好的代碼是,第一運行效率是足夠高的,這個能用客觀數據表明,如果某個大神寫同樣的功能性能比我高很多倍,我同樣會瞠目結舌,這個和語言無關;第二是足夠普通和直白的,見過好的代碼直觀得猶如注釋,很平凡,但很偉大,我比較討厭那種明明用直白簡單的語法能做到的事情非要為了顯示自己牛叉而用上一些所謂的高級特性讓人頭暈目眩,並冠以「這樣寫比較簡略」、「這是高級特性」等等這樣的名頭,我認為這是一種很業餘的做法,如果真的喜歡高級特性,那麼請在業餘私人代碼里使用,而不要用在項目里;第三是開發速度足夠快的,很討厭為了用某個技巧而用某個技巧,這種情況下無論你嘴上說「xx方法」如何如何簡單,但實際上你為了搬這個方法上來已經浪費了大量時間,這些時間本來應當被用來實現代碼或思考更好更加高效的解決方案,或者加快項目進度,你可能會說「這樣寫代碼量比較少」,我們都知道開發過程中大多數時間不是在敲代碼而是在設計、調試和維護,你為了減少一半的代碼而在這三項上用了更多的時間請問這真的值得么?
回歸Scala。Scala集合函數式編程和面向對象編程的特性,使它的功能和擴展能力得到了極大的提升,如果之前長期使用java,那麼初看scala的確會有各種「瞠目結舌」。但必須牢記的是:用Scala不是為了讓你寫的代碼瞠目結舌,而是為了提高效率,提高效率,提高效率!一切違背這一初衷的行為都是一種退化。object ChristmasTree extends DecorationBuilder {
def main(args: Array[String]) {
-/.
--&>*&<--
.
/.
./.|..
/.oxo.
./.*.|.x..
/.oo.|.oo.
./.oxo.|.***..
/.*.oo.|.*.oo..
|||
}
}
當然不能少了扁平化傳參 「:_*」
不夠瞠目結舌,但是寫出這段代碼的時候,我感受到了生命的大和諧。
import scala.annotation.tailrec
/**
* 一個簡單的Y-組合子實現
*/
object YCombiner extends App {
/**
* Y-組合子的實現函數
*
* @param function 需要被遞歸執行的函數
* @tparam T 函數遞歸元素類型
* @return 可遞歸執行的函數
*/
def Y[T](function: (T =&> T) =&> (T =&> T)): (T =&> T) = function(Y(function))(_)
@tailrec
val fibonacci = Y[Int] { f =&> n =&> if (n == 0) 0 else if (n == 1) 1 else f(n - 2) + f(n - 1) } //計算斐波那契數列測試代碼
(0 to 10) foreach { i =&> println(fibonacci(i)) }
}
分享兩個實用的:
# 按多個欄位排序List
case class Student(name: String, age: Int, score: Int)
List(
Student("a", 14, 60),
Student("b", 15, 80),
Student("a", 15, 70)
).sortBy(s =&> (s.age, s.score))
輸出:List(Student(a,14,60), Student(a,15,70), Student(b,15,80))
# 將列表分割成固定大小的子列表
sliding方法使用滑動窗口的方式分割列表,使用起來非常靈活。該方法接受兩個參數,size參數設置窗口大小,step參數設置每次滑動需要滑過的元素個數。例如將列表的每10個元素分成一組,代碼如下:
val list = (a to z).map(_.toString)
list.sliding(10, 10).toList
輸出:
List(Vector(a, b, c, d, e, f, g, h, i, j), Vector(k, l, m, n, o, p, q, r, s, t), Vector(u, v, w, x, y, z))
更多技巧見:Scala第一印象:單行代碼示例
歡迎訪問PlayScala社區(Play Framework amp;amp; Scala amp;amp; Akka 技術交流平台)
推薦閱讀: