4

如果我这样做没有意义吗

type Point = 
    struct
        val Row: int
        val Column: int

        new (row, column) = if row >= 0 && column >= 0 then { Row = row; Column = column }
                            else failwith "Cooridinators must be non-negative!" 
        // This is not a valid object construction
        static member (+) (x: Point, y: Point) = Point (x.Row + y.Row, x.Column + y.Column)
        static member (-) (x: Point, y: Point) = Point (x.Row - y.Row, x.Column - y.Column)
        static member (*) (x: Point, a) = Point (x.Row * a, x.Column * a)
        static member (*) (a, x: Point) =  Point (x.Row * a, x.Column * a)
    end

如果它是一个类,那么也许我可以在绑定期间引发异常do,但是在结构中没有do,我应该怎么做?

我发现可以在之后添加另一个构造函数failwith来解决这个问题,但它提出了另一个问题,我怎样才能调用隐式构造函数?我必须先明确地构造它吗

new () = { Row = 0; Column = 0} 
// Error structs auto supports a default constructor

如果我只是使用默认构造函数执行此操作

new (row, column) = if row >= 0 && column >= 0 then { Row = row; Column = column }
                    else
                        failwith "Cooridinators must be non-negative!"
                        new Point () // error

在我看来,Point ()返回一个单位而不是Point?

4

3 回答 3

9

我认为 F# 编译器会抱怨,因为构造函数应该总是有一个结构:

new ( 模式 ) = 表达式 { 初始化 } [then 表达式 ]

因此,初始化字段的部分不能嵌套在if任何其他表达式之下或内部。您可以在初始化之前或之后(如果添加then关键字)抛出异常。(这对于具有继承的类很重要,但我认为它对结构没有任何影响。)

因此,编写代码的一种方法是编写:

type Point = 
    struct
        val Row: int
        val Column: int

        new (row, column) = 
          if row < 0 || column < 0 then failwith "Cooridinators must be non-negative!"
          { Row = row; Column = column }          

        // (Static members omitted)
    end

请注意,我必须否定条件,因为您需要指定要抛出异常的情况(而不是说何时可以构造对象)。另一种选择是:

new (row, column) = 
  { Row = row; Column = column }          
  then if row < 0 || column < 0 then failwith "Cooridinators must be non-negative!"
于 2013-01-16T00:45:12.213 回答
4

您还有另一种方法可以在初始化部分抛出异常:

new (row, column) = 
  { Row = ((if row < 0 || column < 0 then failwith "Coordinators must be non-negative!"); row); 
    Column = column }

请记住,验证结构构造函数并不总是一个好主意。正如您所发现的,您无法控制默认构造函数的初始化。如果它是一个类,您可以确保以您想要的方式验证所有构造函数。

于 2013-01-16T07:54:23.007 回答
1

这是一个老问题。但是,没有一个答案提到这一点:我认为惯用的 F# 方式根本不抛出异常!为此,您可以使用 a ,如果所有条件都满足并且出现问题static member tryCreate,它将返回。然后,您将遵循选项类型的踪迹来编写逻辑代码,而不是处理异常!我还认为 F# 记录可能也是一种更惯用的方式,除非您明确需要 struct 用于某些非常特定的目的。 Some PointNone

于 2019-01-08T13:25:35.060 回答