如果我这样做是不合理的
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
?
答案 0 :(得分:8)
我认为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!"
答案 1 :(得分:4)
您还有另一种方法可以在初始化部分中抛出异常:
new (row, column) =
{ Row = ((if row < 0 || column < 0 then failwith "Coordinators must be non-negative!"); row);
Column = column }
请记住,验证结构构造函数并不总是一个好主意。如您所知,您无法控制默认构造函数的初始化。如果它是一个类,您可以确保以您希望的方式验证所有构造函数。
答案 2 :(得分:0)
这是一个古老的问题。但是,没有任何答案提到这一点:我认为惯用的F#方式是根本不抛出异常!为此,您可以使用static member tryCreate
,如果满足所有条件,则返回Some Point
,如果出现问题则返回None
。然后,您将遵循选项类型的踪迹来编写逻辑代码,而不用处理异常!我也认为F#记录可能也是一种惯用的方式,除非您出于某些非常特定的目的明确需要使用struct。