16

我正在尝试在 F# 中创建一个额外的构造函数来执行一些额外的工作(即读取基本的 csv 文件),如下所示:

type Sheet () =
  let rows = new ResizeArray<ResizeArray<String>>()
  let mutable width = 0

  new(fileName) as this = 
    Sheet() 
    then
      let lines = System.IO.File.ReadLines fileName
      for line in lines do
        let cells = line.Split ','
        rows.Add(new ResizeArray<String> (cells)) //line 16
        if cells.Length > width then width <- cells.Length

但我收到以下错误:

Error   1   The namespace or module 'rows' is not defined   C:\Users\ga1009\Documents\PhD\cpp\pmi\fsharp\pmi\Csv.fs 16
Error   2   The value or constructor 'width' is not defined C:\Users\ga1009\Documents\PhD\cpp\pmi\fsharp\pmi\Csv.fs 17
Error   3   The value or constructor 'width' is not defined C:\Users\ga1009\Documents\PhD\cpp\pmi\fsharp\pmi\Csv.fs 17

我究竟做错了什么?

4

2 回答 2

32

正如 Daniel 指出的那样,F# 设计是您有一个主构造函数,它通常采用类所需的所有参数并执行初始化。其他构造函数可以为参数提供默认值,也可以根据其他信息计算它们。

在您的情况下,我认为最好的设计是rows作为构造函数参数传递。然后您可以添加两个额外的构造函数(一个加载文件,另一个提供空列表)。

这使代码更简单一些,因为您不必检查是否提供了参数(如 Daniel 的版本)。我还做了一些其他的简化(即计算width功能并使用序列推导 - 如果Sheet不修改数据,你也可以避免使用ResizeArray):

type Sheet private (rows) =  
  // The main constructor is 'private' and so users do not see it,
  // it takes columns and calculates the maximal column length
  let width = rows |> Seq.map Seq.length |> Seq.fold max 0

  // The default constructor calls the main one with empty ResizeArray
  new() = Sheet(ResizeArray<_>())

  // An alternative constructor loads data from the file
  new(fileName:string) =
    let lines = System.IO.File.ReadLines fileName 
    Sheet(ResizeArray<_> [ for line in lines -> ResizeArray<_> (line.Split ',') ])
于 2012-08-21T15:41:57.987 回答
6

rows并且width不在范围内。您可以让成员获取/设置它们,或者(我的建议)使具有最多 args 的构造函数成为主要构造函数:

type Sheet (fileName) =
  let rows = new ResizeArray<ResizeArray<string>>()
  let mutable width = 0

  do
    match fileName with 
    | null | "" -> ()
    | _ ->
      let lines = System.IO.File.ReadLines fileName
      for line in lines do
        let cells = line.Split ','
        rows.Add(new ResizeArray<string> (cells)) //line 16
        if cells.Length > width then width <- cells.Length

  new() = Sheet("")

通常,辅助构造函数旨在成为主构造函数的重载,因此它们无法与类内部(字段)进行交互。这鼓励了单一的初始化路径(和更好的设计)。

于 2012-08-21T14:09:18.797 回答