通过简单的F#模式匹配转换,是否可以在没有警告的情况下忽略不匹配的值?

通过简单的F#模式匹配转换,是否可以在没有警告的情况下忽略不匹配的值?,f#,pattern-matching,transformation,F#,Pattern Matching,Transformation,所以,我之前问过这个问题: 我正在查看发布的代码,我想知道是否可以编写此代码而不产生警告: let [|a;b;c;d|] = s.Split [|'.'|] IP(parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d) 有没有可能为比赛模式做些什么?没有添加活动模式之类的东西?我想让代码尽可能简单。。。我可以在不大幅更改此代码的情况下执行此操作吗 注:警告如下 警告:此表达式上的模式匹配不完整。例如,值“[|;;;;;

所以,我之前问过这个问题:

我正在查看发布的代码,我想知道是否可以编写此代码而不产生警告:

let [|a;b;c;d|] = s.Split [|'.'|]
IP(parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)
有没有可能为比赛模式做些什么?没有添加活动模式之类的东西?我想让代码尽可能简单。。。我可以在不大幅更改此代码的情况下执行此操作吗

注:警告如下

警告:此表达式上的模式匹配不完整。例如,值“[|;;;;;124;]可能表示模式未涵盖的情况

你可以试试

#nowarn "25"
在部分函数之前

但是你当然禁用了一个警告,我想这会关闭整个文件。我记得看到了一种只对文件的一部分禁用警告的方法,但我现在找不到它

还有编译器选项
--nowarn:25
,但这更糟糕,因为它适用于整个项目


要正确执行此操作,需要将两行替换为三行:

match Array.map parseOrParts (s.Split [|'.'|]) with
| [|a;b;c;d|] -> IP(a,b,c,d)
| _ -> failwith "Oh no!"   // preferably, your exception of choice goes here.

请注意,警告告诉您,如果String.Split调用后没有正好4个元素,您将得到一个

正如其他人所说,消除警告的最好方法是

match s.Split(...) with
| [| a; b; c; d |] -> blah(a,b,c,d)
| _ -> raise <| new Exception("Expected exactly 4 parts") // or whatever
将s.Split(…)与
|[a;b;c;d |]->诸如此类(a,b,c,d)
|我知道你写了“没有添加活动模式之类的东西”,但我还是会发布一个使用它们的解决方案。它们是此类问题的完美匹配,并且是相当标准的F#特性,因此您没有理由想要避免它们。在这里使用活动模式无疑会使代码更具可读性

(如果你是F#初学者,我无法理解为什么你想从一个简单的解决方案开始——无论如何,这可能是你最终学习主动模式的一个很好的动机:-),它们并不像第一眼看到的那么难)

如果字符串格式为IP地址(由四个子字符串组成,以“.”分隔),则可以定义匹配的活动模式:

这是允许您在字符串不正确时处理该情况的正确方法。当然,您可以定义一个永不失败的版本(如果字符串格式错误,则返回例如0.0.0.0):


我想大多数人都会同意这更具可读性。当然,如果您只想为一个单一用途的脚本编写简单的脚本,那么您可以忽略警告,但对于任何更大的脚本,我更喜欢活动模式。

是的,它会处理整个文件。不完全是我想要的,但还是很高兴知道!:)作为对第二部分的回应:这是可行的,只是它不会完全按照您所写的那样使用代码。。。我将其更改为:match s.Split[|'。|]|>Array.map parserparts with\n |[| a;b;c;d |]->IP(a,b,c,d)\n | x->failwithf“IP无效(%a)。”x\n(抱歉,我不知道如何格式化此注释)是的,最初缺少
(s.Split[|'。
)的参数。哎呀,我写得很快,没有测试。修正了。您的第一个活动模式似乎毫无意义,因为您可以直接使用
match
。它提供的唯一东西是抽象的
IPString
,这并不是真正的问题所在。就我个人而言,我会使用
System.Net.IPAddress.TryParse
,这样我的代码就不会在第一次遇到IPv6地址时可怕地死去。
let (|IPString|_|) (s:string) =
  match s.Split('.') with
  | [|a;b;c;d|] -> Some(a, b, c, d) // Returns 'Some' denoting a success
  | _ -> None                       // The pattern failed (string was ill-formed)

match s with 
| IPString(a, b, c, d) ->  
    // Matches if the active pattern 'IPString' succeeds and gives
    // us the four parts of the IP address (as strings)
    (parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)
| _ -> failwith "wrong format"
// This active pattern always succeeds, so it doesn't include the "|_|" part 
// in the name. In both branches we return a tuple of four values.
let (|IPString|) (s:string) =
  match s.Split('.') with
  | [|a;b;c;d|] -> (a, b, c, d)
  | _ -> ("0", "0", "0", "0")

let (IPString(a, b, c, d)) = str
(parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)