2013-04-07 156 views
3

問題是:私有函數vs嵌套函數

何時使用私有函數以及何時使用嵌套函數? (我問F#但也許答案可以在其他功能的語言有關)

一個小例子

namespace SomeName 

module BinaryReaderExt = 
    open System.IO 

    let seek (reader : BinaryReader) positions = 
     reader.BaseStream.Seek(positions, SeekOrigin.Current) |> ignore 

module Mod = 
    open System.IO 

    let private prFun reader:BinaryReader = 
     //do something 
     BinaryReaderExt.seek reader 10L 


    let outerFun (stream :System.IO.Stream) = 
     let reader = new System.IO.BinaryReader(stream) 
     let seek = BinaryReaderExt.seek reader 

     let nestedFun() = 
      seek 10L 
      //do something 

     nestedFun() 
     prFun reader 

這是一個巨大的獎賞,即在嵌套函數可以從更高的範圍內使用的數據。也不污染周圍的模塊。但看起來很笨拙,不是嗎?特別是當有一些大的嵌套功能

相反,私人功能可以公開並被測試。看起來它們看起來更具可讀性

你的意見是什麼?

+1

在真正的代碼中看到'let private'非常少見 - 我認爲使用私有方法創建類型會比較普遍 – 2013-04-07 06:41:24

+0

我同意'let private'不是很常見,但我認爲可能僅僅是因爲F#的傳統功能。我其實很喜歡'讓私人',並發現它非常有用(當私人功能是一個獨立的功能)。 – 2013-04-07 13:26:57

+1

私人模塊功能的一個刺激...當試圖在F#Interactive中運行它們時...我得到這個「錯誤FS1094:'myPrivateFunction'的值無法從此代碼位置訪問。我必須刪除'private',將函數添加到F#Interactive中,並記得在完成時替換'private'。 – Wally 2015-03-26 18:04:13

回答

0

嵌套函數可以使用更高範圍的數據是一個很大的好處。也不污染周圍的模塊。

我同意你的觀點。 我的建議是保持功能在正確的範圍。例如,如果函數僅用於一個地方,最好是嵌套函數。例如,將loop向上移動並使其成爲private函數沒有意義。

let length xs = 
    let rec loop acc = function 
     | [] -> acc 
     | _::xs -> loop (acc + 1) xs 
    loop 0 acc 

但就是看似笨拙,不是嗎?特別是當有一些大的嵌套功能

如果你需要大的嵌套函數,那很可能你做錯了。它們應該被分解成多個小嵌套函數,或者最外面的函數應該被轉換爲一個類型。

相反,私人功能可以公開並進行測試。看起來他們看起來更具可讀性。

可讀性是一個主觀的問題。我認爲組織問題更重要。嵌套函數的要點是它們很簡單,可以通過測試最外層函數來測試。

當函數具有更多適用性時,可以將它們放入實用程序模塊並在需要時打開該模塊。請注意,除標記功能外,還有其他技術可以隱藏功能private。例如,您可以使用fsi文件來指示公開的接口。

+1

不幸的是,有些情況下你不能將函數分解成小的函數,因爲那些小函數沒有意義。另外我還必須補充一點,問題是關於只有作爲另一個函數的一部分纔有意義的函數(在我的例子中,outerFun),並不意味着它可以被模塊中的其他函數重用。也許'私人'在這裏是不對的。謝謝你的好回答! – 2013-04-07 12:33:45

4

我在模塊中經常使用private函數 - 通常用於模塊中其他函數使用但不需要暴露給外部代碼的「幫助」函數。

private函數的另一個用例是簡單地使代碼更具可讀性。如果一個函數嵌套在另一個函數中,但是它的讀取時間太長 - 例如,如果嵌套函數的代碼佔函數長度的一半以上 - 我通常會將它移動到模塊級別並使其成爲private,因此調用者函數的代碼更易於理解。