「暗黙的なオーバーロード」は可能ですか? | f#,types,overloading,arguments,implicit

私は次の例を持っています:

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#の初心者です。 3つの format
オーバーロードは、( write
の異なるオーバーロードを呼び出していても)その本体が同じである間に、引数の型だけが異なります。何らかの形でフォーマット関数を1つに減らすことは可能でしょうか、おそらくインライン化されていますか?

私がここでのポイントを完全に見逃している場合はお詫びしますが、私はその問題に関する多くの情報を見つけることができませんでした。

ベストアンサー

私はあなたが書いた方法がおそらく最良の選択肢だと思う。

ボクシングをしたくない場合、オーバーロードされた write
関数が必要です。なぜなら、異なるタイプのシリアル化を別々に実装する必要があるからです。 inline
関数では特定のインスタンスまたは静的メソッド on が必要な値しか得られないため、
inline 特定の過負荷ではありません。

いくつかの重複を避ける妥当な解決策は、オーバーロードされた関数を1つだけ定義して(たとえば 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
に関して、引数の型が特定のメンバ(インスタンスまたは静的)を実装するように指定することができますが、特定のオーバーロードがあるとは言えません。静的メンバー
Write を持つ3つのタイプ( int16
string 、…)のすべてのラッパーを作成した場合は、

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
を呼び出すときにいくつかの追加コードを記述する必要があるさらに複雑な解決策ですので、実際にはそのアプローチを使用しません(ただし、存在することを知ることは有益かもしれません)。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です