F#如何定义仅泛型参数为指定类型时生效的类实例方法
实现方案
问题根源
你当前的代码报错是因为Add方法定义在未做约束的泛型类Arr<[<Measure>] 'Index, 'Value>内部,此时'Value代表任意类型,编译器无法确认'Value类型元素和float类型元素相加的合法性,同时也无法实现「仅当'Value为float时方法可用」的限制。
最优实现:扩展方法
F#中针对这类「特定泛型参数下才暴露成员」的需求,最标准的实现方式是使用针对构造泛型类型的扩展方法,既可以保证编译期类型校验,也不会为其他'Value类型的Arr实例暴露多余方法。
步骤1:调整原类型定义
删除Arr类内部的Add方法:
type ImArr<[<Measure>] 'Index, 'Value>(values: array<'Value>) = let values = values |> Array.copy member internal _.Values : array<'Value> = values member this.Item with get(index: int<'Index>) = values.[int index] type Arr<[<Measure>] 'Index, 'Value>(values: array<'Value>) = let values = values |> Array.copy member this.Item with get(index: int<'Index>) = values.[int index] and set(index: int<'Index>) (value: 'Value) = values.[int index] <- value member internal _.Values : array<'Value> = values
步骤2:定义针对float类型的扩展方法
open System.Runtime.CompilerServices // 扩展方法所在模块,和Arr放在同一命名空间下即可自动生效 [<Extension>] module ArrFloatExtensions = [<Extension>] member Add(this: Arr<'Index, float>, b: ImArr<'Index, float>) = if this.Values.Length <> b.Values.Length then invalidArg (nameof b) "Cannot add arrays of different lengths" let mutable i = 0 while i < this.Values.Length && i < b.Values.Length do this.Values.[i] <- this.Values.[i] + b.Values.[i] i <- i + 1
效果验证
- 当你创建
Arr<_, float>类型的实例时,可以正常调用Add方法,编译运行都不会报错 - 当你创建其他
'Value类型的Arr实例时,编译器不会提示Add方法,强行调用会直接报编译错误,完全符合你要的限制要求
可选拓展
如果后续需要支持int、float32等多种数值类型的加法操作,可以使用静态解析类型参数(SRTP)定义泛型扩展方法,约束'Value支持加法操作即可,不需要为每个类型单独写扩展。
内容的提问来源于stack exchange,提问作者Matthew Crews
相关产品推荐
相关产品推荐

