我们可以使用像
这样的展开函数来展开类似type Address = Address of string
的类型
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
所以str
的类型为string
,但如果有类似这种方式,那么方法就不会有效:
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite c) = c
会产生错误
let unwrap (Composite c) = c;;
------------^^^^^^^^^^^
error FS0019: This constructor is applied to 1 argument(s) but expects 2
我可以以某种方式将复合类型解包为一个简单的元组吗?
答案 0 :(得分:6)
您将类型定义为具有命名字段的单个案例区分联合:
type Composite = Composite of integer:int * someStr:string
以这种方式定义时,union case的字段不是简单的元组。它们以特殊方式处理,例如,名称在编译代码中用作属性名称。模式匹配不会自动将元素转换为元组,因此您必须单独打开它们:
let unwrap (Composite(i, s)) = i, s
但是,您也可以定义单个案例并集,其中字段是普通元组。 (请注意,您需要围绕元组类型的括号 - 否则,它最终也会以特殊方式处理,但项目将被编译为Item1
和Item2
。)
type Composite = Composite of (int * string)
使用此定义,您的unwrap
函数将正常工作并提取元组值:
let unwrap (Composite c) = c
您还可以使用嵌套模式来获取数字和字符串,如上例所示:
let unwrap (Composite(i, s)) = i, s
根据您是否编写A of (T1 * T2)
或是否编写A of T1 * T2
,这种行为有所不同这一事实有点微妙 - 这两者可能需要区分,以便编译器知道是否编译字段作为两个单独的字段或作为System.Tuple<T1, T2>
类型的一个字段。我无法想象任何其他情况下差别很重要。
答案 1 :(得分:4)
这些对我有用。它是您的matching语法,通常您会发现它与匹配语句一起使用,但它在l.h.s.上。作业。可能,这最初对于元组来说是最有意义的,但是你可以在任何结构中使用它。
let (a,b) = (1,2)
let (x,_) = (4,5)
另外两件有趣的事情:
let (head::tail) = [1;2;3;4]
FSI响应警告FS0025:此表达式上的不完整模式匹配。例如,值&#39; []&#39;可能表示该模式未涵盖的案例。
&#34;那是真的,&#34;你大声说出来。 &#34;我应该将其表示为匹配并包含空列表作为可能性&#34;。最好将这些类型的警告冒充为真正的真实错误(参见:warn as error,例如 - warnaserror +:25 )。不要忽视它们。通过习惯或编译器强制方法解决它们。对于单个案例,存在零歧义,因此代码开启。
更有用+有趣的是l.h.s.上的匹配语法功能分配。这很酷。对于精辟的函数,你可以解压缩里面的东西,然后在一个步骤中对内部进行操作。
let f (Composite(x,y)) = sprintf "Composite(%i,%s)" x y
f (Composite(1,"one"))
> val it : string = "Composite(1,one)"
关于您的代码:
type Address = Address of string //using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite(c,_)) = c
let cval = Composite(1,"blah")
unwrap cval
解决方法:
let xy = Composite(1,"abc") |> function (Composite(x,y))->(x,y)
...但是更好的方式,假设你想保留单个案例DU的命名元素将是...
let (|Composite|) = function | Composite(x,y)->(x,y)
let unwrap (Composite(x)) = x
let unwrap2 (Composite(x,y)) = (x,y)
......不是通过单个案例DU严格分解,而是通过单个案例分解Active Pattern
最后,您可以将方法附加到Composite结构...
module Composite =
let unwrap = function | Composite(x,y)->(x,y)
关于使用此技术的最佳讨论之一是here
另外,看看unwrap给我们的签名:一个复合(斜体)的函数,并返回一个int(粗体)
Signature - val unwrap: Composite - &gt;的 INT 强>
答案 2 :(得分:4)
在你的情况下,你可以写:
type Composite = Composite of int * string
let unwrap (Composite (a, b)) = a, b
对应于:
let unwrap x =
match x with
| Composite (a, b) -> a, b
这里发生的是F#允许您使用任意复杂的模式匹配来内联解构函数参数。在引入单个案例DU时经常会提到这一点,但很少得出结论,这导致人们相信单个案例DU在某种程度上是特殊的。
事实上,当你有多个案例时,你可以使用它(只要每个案例绑定同一组变量):
type Composite = Composite of int * string | JustString of string
let unwrapString (Composite (_, s) | JustString s) = s
但大部分时间,你都会在更简单的类型上进行模式匹配,比如元组:
let f (a, b, c) = ...
甚至更奇怪的是:
let f () = ...
这里()
是单位类型的唯一值的模式匹配 - 而不是某种无参数函数的视觉标记&#34;,因为它经常被描述。 / p>