如何在 F# 中使用字符串类型列表的自动 属性 声明 class?
How to declare class with auto property of type list of strings in F#?
我很难理解我应该如何在 F# 中定义 class,因为我的属性还没有声明值。相当于 c# 代码的东西:
class Entity
{
public string Name { get; set; }
public List<string> Favorites { get; set;}
}
我只能声明类型定义为
type Entity =
member val Name = "" with get, set
当我分配 null 时,Name 的类型将为 null。
如评论中所述,F# 中不推荐使用 null
值,因此最好尽可能避免使用它们。默认情况下,F# 类型也不允许 null
,因此如果您使用不可变的 F# list
类型,那么您最好的选择是将 属性 初始化为一个空列表:
type Entity() =
member val Name = "" with get, set
member val Favorities : list<string> = [] with get, set
请注意,我添加了一个类型注释 list<string>
,因为编译器无法仅从代码中推断空列表包含字符串,否则您最终会得到 list<obj>
。
C# List
类型在 F# 中缩写为 ResizeArray
并且由于这是 .NET 类型,因此可以将此类型的属性初始化为 null
:
type Entity() =
member val Name = "" with get, set
member val Favorities : ResizeArray<string> = null with get, set
我想如果您正在使用一些非 F# 友好的 ORM 和类似的东西,这可能会有用,但否则,使用它可能会给您带来很多痛苦和意外错误。
最接近该 C# 代码的 F# 是这样的:
type Entity() =
member val Name = Unchecked.defaultof<string> with get, set
member val Favorites = Unchecked.defaultof<string list> with get, set
但是,这是一个糟糕的 F#,这就是为什么它被故意设计得看起来很丑。 F# 不鼓励使用默认值、可空引用和变异。
因此,您应该决定一些合理的默认值:
type Entity() =
member val Name = "" with get, set
member val Favorites = [] with get, set
或者您应该使用 Option
类型使值显式可选,并使用 None
作为默认值,避免在运行时出现空引用异常:
type Entity() =
member val Name = None : string option with get, set
member val Favorites = None : string list option with get, set
注意:我在上面使用的 list
与 C# List
不同。
我在您的评论中看到您使用 member val
的原因是为了 Newtonsoft.Json。将它与 F# 记录一起使用曾经是一个问题,但现在它工作得很好。以下是使用 Newtonsoft.Json 10.0.3 测试的:
type Foo =
{
x: int
y: float
}
open Newtonsoft.Json
let foo = JsonConvert.DeserializeObject<Foo>("{\"x\":1,\"y\":1.2}")
printfn "%A" foo
// {x = 1;
// y = 1.2;}
对于需要默认构造函数和可变字段的序列化库,您可以将 [<CLIMutable>]
属性放在记录上,它会提供这些(但在 F# 中不可见,以保持安全保证)。
我很难理解我应该如何在 F# 中定义 class,因为我的属性还没有声明值。相当于 c# 代码的东西:
class Entity
{
public string Name { get; set; }
public List<string> Favorites { get; set;}
}
我只能声明类型定义为
type Entity =
member val Name = "" with get, set
当我分配 null 时,Name 的类型将为 null。
如评论中所述,F# 中不推荐使用 null
值,因此最好尽可能避免使用它们。默认情况下,F# 类型也不允许 null
,因此如果您使用不可变的 F# list
类型,那么您最好的选择是将 属性 初始化为一个空列表:
type Entity() =
member val Name = "" with get, set
member val Favorities : list<string> = [] with get, set
请注意,我添加了一个类型注释 list<string>
,因为编译器无法仅从代码中推断空列表包含字符串,否则您最终会得到 list<obj>
。
C# List
类型在 F# 中缩写为 ResizeArray
并且由于这是 .NET 类型,因此可以将此类型的属性初始化为 null
:
type Entity() =
member val Name = "" with get, set
member val Favorities : ResizeArray<string> = null with get, set
我想如果您正在使用一些非 F# 友好的 ORM 和类似的东西,这可能会有用,但否则,使用它可能会给您带来很多痛苦和意外错误。
最接近该 C# 代码的 F# 是这样的:
type Entity() =
member val Name = Unchecked.defaultof<string> with get, set
member val Favorites = Unchecked.defaultof<string list> with get, set
但是,这是一个糟糕的 F#,这就是为什么它被故意设计得看起来很丑。 F# 不鼓励使用默认值、可空引用和变异。
因此,您应该决定一些合理的默认值:
type Entity() =
member val Name = "" with get, set
member val Favorites = [] with get, set
或者您应该使用 Option
类型使值显式可选,并使用 None
作为默认值,避免在运行时出现空引用异常:
type Entity() =
member val Name = None : string option with get, set
member val Favorites = None : string list option with get, set
注意:我在上面使用的 list
与 C# List
不同。
我在您的评论中看到您使用 member val
的原因是为了 Newtonsoft.Json。将它与 F# 记录一起使用曾经是一个问题,但现在它工作得很好。以下是使用 Newtonsoft.Json 10.0.3 测试的:
type Foo =
{
x: int
y: float
}
open Newtonsoft.Json
let foo = JsonConvert.DeserializeObject<Foo>("{\"x\":1,\"y\":1.2}")
printfn "%A" foo
// {x = 1;
// y = 1.2;}
对于需要默认构造函数和可变字段的序列化库,您可以将 [<CLIMutable>]
属性放在记录上,它会提供这些(但在 F# 中不可见,以保持安全保证)。