2012-01-11 31 views
1

我有下面的例子:「隱式重載」可能嗎?

所有的
type Stream (capacity) = 
    let data = Array.zeroCreate capacity 
    member private s.position = ref 0 
    static member private encoder = new Text.UTF8Encoding() 
    static member private write (x, o, a : byte[]) = for i = 0 to 3 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256) 
    static member private write (x, o, a : byte[]) = for i = 0 to 1 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256s) 
    static member private write (x : string, o : int, a : byte[]) = Stream.encoder.GetBytes(x, 0, x.Length, a, o) 
    static member format (x : int, s) = let a = Array.create s 0uy in Stream.write(x, 0, a); a 
    static member format (x : int16, s) = let a = Array.create s 0uy in Stream.write(x, 0, a); a 
    static member format (x : string, s) = let a = Array.create s 0uy in Stream.write(x, 0, a); a 

首先,比較遺憾的是非常混亂的代碼,我只是在F#初學者。您可能會看到三個format重載僅在參數類型上有所不同,而它們的主體是相同的(儘管調用了不同的重載write)。可能以某種方式將格式函數減少爲1,也許內聯?

我很抱歉萬一我完全忽略了這一點,但我找不到有關此事的很多信息。

+0

這看起來像[模式匹配](http://msdn.microsoft.com/en-us/library/dd233242.aspx)可能更適合。 – 2012-01-11 23:39:35

+1

有沒有辦法做到這一點,沒有拳擊x? – user1098567 2012-01-11 23:44:31

+0

這是一個很好的問題......你寫這個的方式看起來更像是一個OO程序,而不是一個功能性的程序。 – 2012-01-11 23:47:36

回答

3

我認爲你寫它的方式可能是最好的選擇。

如果你不想做拳擊,那麼重載的write函數肯定是需要的,因爲序列化需要以不同的類型實現。使用inline成員在這種情況下也不起作用,因爲inline函數只能請求特定實例或靜態方法它獲取的某些值,但不是特定的重載。

避免一些重複的合理解決方案是僅定義一個重載函數(即write),然後在需要時將其作爲參數顯式傳遞給其他函數。你可以這樣寫:

type Stream (capacity) = 
    let data = Array.zeroCreate capacity 
    member private s.position = ref 0 
    static member private encoder = new Text.UTF8Encoding() 
    static member Write (x, o, a : byte[]) = 
     for i = 0 to 3 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256) 
    static member Write (x, o, a : byte[]) = 
     for i = 0 to 1 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256s) 
    static member Write (x : string, o : int, a : byte[]) = 
     Stream.encoder.GetBytes(x, 0, x.Length, a, o) |> ignore 
    // Format takes a writer function 'f' as the first argument 
    static member Format (x, s) f = let a = Array.create s 0uy in f(x, 0, a); a 

// When you call 'Format' with 'Stream.Write' as an argument, 
// the compiler chooses the right overload for you 
Stream.Format (1s, 100) Stream.Write 
Stream.Format ("foo", 100) Stream.Write 

這樣可以避免定義端的一些代碼重複,但它使用時間更長。如果你不需要像Format這樣的許多函數,那麼最好的方法就是像你最初那樣定義一個重載代碼。

關於inline,可以使用它來指定一個參數的類型應該實現某個特定的成員(實例或靜態),但不能說應該有一個特定的重載。如果你寫的包裝所有這三種類型(int16string,...),其有一個靜態成員Write,那麼你可以寫:

let inline format< ^T when ^T : 
    (static member Write : ^T * int * byte[] -> unit)> (value:^T) size = 
    let a = Array.create size 0uy 
    (^T : (static member Write : ^T * int * byte[] -> unit) (value, 0, a)) 
    a 

...但是這更復雜的解決方案,也需要寫一些當撥打format時需要額外的代碼,所以我不會真的使用這種方法(但知道它存在可能是有用的)。

+0

非常感謝解釋和建議的替代方法! – user1098567 2012-01-12 00:06:53

1

重構format功能很明顯;您可以創建通用格式函數並將不同的Stream.write函數作爲參數傳遞。首先,把泛型函數類的任何成員之前:

    static let formatGeneric writeFunc x s = 
      let a = Array.create s 0uy          
      writeFunc(x, 0, a)          
      a 

,並用它來實例化不同格式的功能:

static member format (x, s) = 
      formatGeneric (fun (x: int, i, a) -> Stream.write(x, i, a)) x s 
    static member format (x, s) = 
      formatGeneric (fun (x: int16, i, a) -> Stream.write(x, i, a)) x s 
    static member format (x, s) = 
      formatGeneric (fun (x: string, i, a) -> Stream.write(x, i, a)) x s 

注意Stream.write寫入的x完整形式和類型註釋以選擇合適的過載。

相關問題