我试图编写一个接受字节数组的函数,并将其转换为参数指定的ADT。这可能在F#中吗?这是我的ADT:
type DataFormat =
| Alphanumeric of string
| Angle16 of float
| Angle32 of float
| Int16 of int
| Int32 of int
我已经尝试了十种不同的格式化功能规范的方法,但是我无法弄明白......我读了一些关于SO的其他帖子,如this one这些让我觉得认为这比我想象的要复杂得多。这是我最后两次似乎无处可寻的尝试。
// Attempt #1
// This function would require that I pass in a shell
// object as the "format" parameter to make it work, like:
// let converted = fromBytes1 myArray Angle16(0.0)
let fromBytes1 (b : byte[]) (format : DataFormat) =
match format with
| Alphanumeric -> Alphanumeric(BitConverter.ToString(b))
| Angle16 -> // convert 2-bytes into float...omitted
| Angle32 -> Angle32(float (BitConverter.ToSingle(b,0)))
// Attempt #2
// the 'T seems to only specify the underlying type like (float, int)
let fromBytes2<'T> (b : byte[]) =
match 'T with
| Alphanumeric -> Alphanumeric(BitConverter.ToString(b))
| Angle16 -> // convert 2-bytes into float...omitted
| Angle32 -> Angle32(float (BitConverter.ToSingle(b,0)))
我也尝试过使用typeof&lt;&gt;但这似乎只返回基础类型。
答案 0 :(得分:1)
我认为你试图在这里重复使用你的歧视联盟。
使用1:您将它用作标记(或erlang术语中的原子)来向函数指示您期望的内容。然后,它看起来像这样:
type DataType = | Int | Bool // without any data items associated.
let readExpected (valueType : DataType) (data : byte[] ) =
match valueType with
| DataType.Int -> // parse the int from data and do something with it
| DataType.Bool -> // parse the boolean representation from data ...
使用2:您使用union作为真正的ADT。那么它将是你函数的返回值:
type ADT = | Int of int | Bool of bool // now they have data
let read (data : byte[]) : ADT =
let wireType = data.[0]
match wireType with
| 2uy -> Int(readInt data) // return the parsed int as ADT.Int
| 3uy -> Bool(readBool data) // return the parsed bool as ADT.Bool
| _ -> failwith "Unknown wire type in data."
当然,你可以试着混合这两种方法。
type ADT = | Int of int | Bool of bool // now they have data
let readExpected (data : byte[]) (expectedType : ADT) : ADT =
match expectedType with
| Int(_) -> Int(readInt data)
| Bool(_) -> Bool(readBool data)
如果您不喜欢使用某些虚假数据内容明确地编写expectType的方法,您可以选择这样一个简单的解决方案:
type ADT = | Int of int | Bool of bool // now they have data
let IntType = Int(0)
let BoolType = Bool(false)
let readExpected (data : byte[]) (expectedType : ADT) : ADT =
match expectedType with
| Int(_) -> Int(readInt data)
| Bool(_) -> Bool(readBool data)
// caller code:
let intValue = readExpected data IntType
let boolValue = readExpected data BoolType
这里可能有意义,切换两个参数的顺序。
如果实际上并非如此,也许不假装它是动态的。
如果调用者能够在上面的代码中指定IntType
,您可以简单地为每种类型创建一个函数。
type ADT = | Int of int | Bool of bool // now they have data
let readInt data =
Int( foo data) // foo data is my lazy way of saying: However you parse it ;)
let readBool data =
Bool( if data.[0] = 0uy then false else true )
// caller code:
let intValue = readInt data
let boolValue = readBool data
请注意,所有readXXX函数都具有相同的类型:byte[] -> ADT
。因此,如果您计划通过合成来指定消息类型,则可以利用这一事实。