Programming In Scala Reading Note 7

來源:互聯網
上載者:User

標籤:style   java   color   使用   strong   os   

函數和閉包1 成員方法

java中函數存在的方式,我們給一個類追加一個功能的途徑就是給他追加一個方法。

 

2 本地方法

所謂的本地方法就是存在於一個方法內部的方法。

如果一個類中有一個方法是private的,且只有一個方法使用到他,那麼這個方法完全可以被定義為一個本地方法

 

3 函數式一等公民

方法分為:

1 方法名稱  def add

2 方法參數      (a:Int, b:Int)

3 賦值符號              =

4 方法體                  a + b

其實,(a:Int, b:Int) => a + b,就構成了一個基本的函數了,只不過它的名字叫做add,所以說我們可以這麼調用一個函數:

add(1, 2),傳回值為3

也可以這麼調用這個函數:

((a:Int, b:Int) => a + b)(1, 2),傳回值也是3

 

現在就應該相對明朗了,我們可以把一個函數賦給一個val變數,這樣這個變數就是一個函數了,如:

val addition = (a:Int, b:Int) => a + b

那麼addtion(11, 12)就等於23。

 

另外方法可以被當成函數的參數來使用,如List的foreach方法,它需要一個方法作為參數

val list = List(1, 2, 3, 4, 5)

list.foreach(element => println(element + 1))

另外一個filter方法,

val evenList = list.filter(element => element % 2 == 0)

 

4 更加簡潔

像上面的紅字部分提供了簡寫方法,而實際上完整的格式應該是list.foreach((element:Int) => println(element + 1))

我們沒有理由去寫這麼完整的東西,除非編譯器無法確定這個方法參數的類型了。

 

還有更加簡潔的方式,預留位置寫法:

用這個例子:val evenList = list.filter(element => element % 2 == 0)

這個例子中只有一個參數,且在方法體中出現一次,那麼可以簡寫為預留位置:

val evenList = list.filter(_ % 2 == 0),就是說,對每一個元素都用_替代。

 

還可以這樣子呢: val threeParamAdd = (_:Int) + (_:Int) + (_:Int)

這也是每一個參數在方法體中出現一次,第一個參數替代第一個_,第二個替代第二個_,以此類推。。。

 

我們盡量去省略參數類型,知道編譯器不能為我們判別出來我們的參數類型。

 

Partially applied functions(部分(不完全)應用(提供)函數):

list.foreach(x => println(x)) 改寫為 list.foreach(println _)

_不僅可以代表單獨的一個參數,還可以代表全部的參數。

當我們沒有給一個方法提供足夠的參數,而只是在方法名後面緊跟一個空格加上一個底線,如println _

 

def println(x: Any) = Console.println(x)

是Predef類中的方法,我們只提供一個println _,方法這個_代表的是這個方法中的所有的參數。

 

def sum(a: Int, b: Int, c: Int) = a + b + c

如果我們把他給一個變數時,可以這麼寫

val threeParamAdd = sum _                部分應用函數

或者

val threeParamAdd = (_:Int) + (_:Int) + (_:Int)      預留位置寫法

或者

val threeParamAdd = (a:Int, b:Int, c:Int) => a + b + c   普通寫法

 

回過來說val threeParamAdd = sum _, 當對這個threeParamAdd進行調用的時候,如threeParamAdd(1, 2, 3),編譯器會看到sum _,然後他知道去找sum函數,發現有三個參數,依次替代,完成計算。

還會有另外的情況,如:

val oneAddSomeAddThree = sum(1, _:Int, 3),這樣的話,我們的oneAddSomeAddThree只允許有一個參數了。

 

如果某個地方整好需要一個函數作為參數,且這個函數可以使用部分應用函數的話,這個時候底線也可以省略。

如:list.foreach(println _) 可以修改成 list.foreach(println)

因為編譯器知道我們寫的這個println是一個函數,而不是別的東西,他會把他認為是一個部分應用函數。

 

5 閉包

引用了自由變數的函數,與這個自由變數一起組成的實體,叫做一個閉包

自由變數,除了函數的參數,以及函數中聲明的變數以外的變數。

綁定變數,函數的參數,以及其他函數編譯時間能夠確定的變數。

 

封閉術語:closed term,不包含自由變數的函數文本。

開放術語:open term,包含了自由變數的函數文本。

 

6 特殊的調用函數的形式

1 重複的參數:

def echo(arr: String*) { arr.foreach(println _) }

arr:String*, 是scala的文法,跟java中的String ... some,相似。

其中*指明這個參數是一個數組,數組元素的類型是String,數組長度為調用方法時給定的字串的個數。

 

如果現在有一個數組,想用以上方法調用,如:

val some = Array("This‘s", "little", "wonderful"),如果直接調用的話,會出錯,echo(some)

這時需要這樣傳遞參數:echo(some: _*)

編譯器會把some中的每一個元素作為參數傳遞給方法。

 

2 命名的參數:

def speed(distance:Float, time:Int) = distance / time

speed(100, 10)

speed(distance = 100, time = 10)

speed(time = 10, distance = 100)

 

3 具有預設值的參數

def nameBreaker(name:String = "Voctrals Lou", breaker:String = " ") = name.split(breaker)

如果我們調用nameBreaker(),返回Array("Voctrals", "Lout")

如果我們提供了其中的值,那麼預設值就不再起作用了,如

nameBreaker(breaker = "_"),傳回值為Array("Voctrals Lou")

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.