2012-01-11 56 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完整形式和类型注释以选择合适的过载。