我有以下示例:
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
的不同重载)。有可能以某种方式将格式函数减少到一个,可能是内联的吗?
我道歉,如果我完全忽略了这一点,但我找不到有关此事的更多信息。
答案 0 :(得分:3)
我认为你写它的方式可能是最好的选择。
如果你不想做拳击,那么肯定需要重载write
函数,因为序列化需要针对不同类型实现不同。在这种情况下使用inline
成员也不起作用,因为inline
函数只需要特定实例或静态方法 on 它获得的某些值,但不是具体超载。
避免一些重复的合理解决方案是仅定义一个重载函数(即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
,您可以使用它来指定参数的类型应该实现某个特定成员(实例或静态),但您不能说应该存在特定的重载。如果您为具有静态成员int16
的所有三种类型(string
,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
时编写一些额外的代码,所以我不会真正使用这种方法(但知道这可能有用)它存在)。
答案 1 :(得分: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
的类型被注释以选择合适的过载。