我有这样的类型:
type TaskRow =
{
RowIndex : int
TaskId : string
Task : Task option
}
Run Code Online (Sandbox Code Playgroud)
函数将返回这些记录的列表,以供进一步处理。有些这样做处理功能仅适用于有关TaskRow地方的项目Task是Some。我想知道最好的方法是什么。
天真的方法会这样做
let taskRowsWithTasks = taskRows |> Seq.filter (fun row -> Option.isSome row.Task)
Run Code Online (Sandbox Code Playgroud)
并将其传递给那些函数,只需假设Task它将永不存在,None并使用Task.Value,如果我不传递该特殊列表,就会冒NRE的风险。这正是当前的C#代码所做的,但是对于F#来说似乎很简单。我不应该“假设”事情,而应该让编译器告诉我什么将起作用。
更具“功能性”的是每次值相关时都进行模式匹配,然后对进行任何操作/不返回任何值(或使用choose类似方法)None,但这似乎是重复的和浪费的,因为同一工作将被重复执行多次。
另一个想法是引入第二种稍有不同的类型:
type TaskRowWithTask =
{
RowIndex : int
TaskId : string
Task : Task
}
Run Code Online (Sandbox Code Playgroud)
然后,原始列表将被过滤到这种“子列表”中,以便在适当的情况下使用。从功能的角度来看,我认为这是可以的,但是我想知道是否有一种更好的,惯用的方式而不求助于这种“帮助类型”。
感谢您的指导!
知道任务已经过过滤是很有价值的,因此拥有两种不同的类型可能会有所帮助。除了定义两个不同的类型(尽管在F#中没什么大不了的),您还可以考虑定义一个通用Row类型:
type Row<'a> = {
RowIndex : int
TaskId : string
Item : 'a }
Run Code Online (Sandbox Code Playgroud)
这使您可以定义这样的投影:
let project = function
| { RowIndex = ridx; TaskId = tid; Item = Some t } ->
Some { RowIndex = ridx; TaskId = tid; Item = t }
| _ -> None
let taskRowsWithTasks =
taskRows
|> Seq.map project
|> Seq.choose id
Run Code Online (Sandbox Code Playgroud)
如果初始taskRows值具有类型seq<Row<Task option>>,则结果taskRowsWithTasks序列具有类型seq<Row<Task>>。