将 "abstract" 方法添加到(F#)记录
Add an "abstract" method to (an F#) record
我创建了以下记录以尝试将 C# class 转换为 F#:
type Days = Days of int
type Value = Value of int
type Item = {
Name: string
Expires: Days
Value: Value
}
我还需要每个项目都有一个... "way" 到 运行 另一个尚未定义的函数 handleDevalue
,它作用于项目本身以操纵项目的 Value
值。
handleDevalue
函数依赖于项目的 Expires
属性,因此每个项目的实现都会不同,唯一的公共线程是函数的名称和签名 (Item -> Item
).
在我正在翻译的 C# 代码中,此方法在 Item
class 上定义为 abstract
并在实例化的每个项目上被覆盖(其中每个项目都是子 class 继承自Item
).
我试过的,不成功到现在:
- 在记录上添加抽象方法:
...} with abstract handleDevalue: Item -> Item
.
1.1 失败原因:IDE告诉我"abstract can't be added here as an augmentation"(或接近相同效果的东西)。 (我对 F# 的了解还不够,甚至不知道它是什么意思,但编译器不会让它编译,所以...不)。
- 在记录中添加
handleDevalue
作为函数:{... HandleDevalue: Item -> Item...}
.
2.1. 失败原因:此功能依赖Expires
属性。显然,记录的字段是相互独立的,此外......函数 "know" 将如何作用于哪个项目(它应该作用于项目本身)?当 "instantiating" 一条记录时(即没有 {...handleDevalue = fun this -> <some implementation code here>
)实现函数时不允许使用 this
关键字。
- 我记得在我创建的每个项目上定义函数(无论如何我应该),但这并没有使用类型系统对我有利。
我希望编译器强制我实现该功能并在我不执行时提醒我。
由于这些方法都失败了,我不知道如何前进。
感谢您提前提出任何建议。
我不太确定你想在这里完成什么,但我会试一试。
为什么不做类似的事情,使用有区别的联合而不是继承?
type Days = Days of int
type Value = Value of int
type Item = {
name: string
expires: Days
value: Value
}
type ItemType =
| FooItem of Item
| BarItem of Item
| BazItem of Item
// ...
let deValue item =
match item with
| FooItem i ->
{
name = i.name
expires = i.expires -1
value = i.value -1
} |> FooItem
| BarItem i ->
{
name = i.name
expires = i.expires -1
value = i.value -10
} |> BarItem
| // etc
想想 C# 程序中实际发生了什么。
您有多个不同的 handleDevalue
实现,每个项目实例都有其中一个与之关联的实现。但是,是什么决定了哪个与哪个项目相配呢?好吧,这是由该项目的特定后代 class 决定的。好的,但是什么决定了实例化哪个后代 class?
某个地方,某个时间点,一定有一个地方以某种方式挑选后代class。让我们假设它看起来像这样:
class Item { public abstract int handleDevalue() { ... } }
class FooItem : Item { public override int handleDevalue() { ... } }
class BarItem : Item { public override int handleDevalue() { ... } }
public Item createItem(string name, Days expires, Value value) {
if (foo) return new FooItem(name, expires, value)
else return BarItem(name, expires, value)
}
所以,看看发生了什么:最终,创建项目的人正在选择最终使用哪个 handleDevalue
实现,然后该实现附加到项目通过 table.
方法实例
现在我们知道了这一点,我们可以在 F# 中做同样的事情。我们只需要明确附加实现即可:
type Item = {
Name : string
Expires : Days
Value : Value
handleDevalue : Item -> Item
}
let handleDevalueFoo item = ...
let handleDevalueBar item = ...
let createItem name expires value = {
Name = name
Expires = expires
Value = value
handleDevalue = if foo then handleDevalueFoo else handleDevalueBar
}
我创建了以下记录以尝试将 C# class 转换为 F#:
type Days = Days of int
type Value = Value of int
type Item = {
Name: string
Expires: Days
Value: Value
}
我还需要每个项目都有一个... "way" 到 运行 另一个尚未定义的函数 handleDevalue
,它作用于项目本身以操纵项目的 Value
值。
handleDevalue
函数依赖于项目的 Expires
属性,因此每个项目的实现都会不同,唯一的公共线程是函数的名称和签名 (Item -> Item
).
在我正在翻译的 C# 代码中,此方法在 Item
class 上定义为 abstract
并在实例化的每个项目上被覆盖(其中每个项目都是子 class 继承自Item
).
我试过的,不成功到现在:
- 在记录上添加抽象方法:
...} with abstract handleDevalue: Item -> Item
.
1.1 失败原因:IDE告诉我"abstract can't be added here as an augmentation"(或接近相同效果的东西)。 (我对 F# 的了解还不够,甚至不知道它是什么意思,但编译器不会让它编译,所以...不)。 - 在记录中添加
handleDevalue
作为函数:{... HandleDevalue: Item -> Item...}
.
2.1. 失败原因:此功能依赖Expires
属性。显然,记录的字段是相互独立的,此外......函数 "know" 将如何作用于哪个项目(它应该作用于项目本身)?当 "instantiating" 一条记录时(即没有{...handleDevalue = fun this -> <some implementation code here>
)实现函数时不允许使用this
关键字。 - 我记得在我创建的每个项目上定义函数(无论如何我应该),但这并没有使用类型系统对我有利。
我希望编译器强制我实现该功能并在我不执行时提醒我。
由于这些方法都失败了,我不知道如何前进。
感谢您提前提出任何建议。
我不太确定你想在这里完成什么,但我会试一试。
为什么不做类似的事情,使用有区别的联合而不是继承?
type Days = Days of int
type Value = Value of int
type Item = {
name: string
expires: Days
value: Value
}
type ItemType =
| FooItem of Item
| BarItem of Item
| BazItem of Item
// ...
let deValue item =
match item with
| FooItem i ->
{
name = i.name
expires = i.expires -1
value = i.value -1
} |> FooItem
| BarItem i ->
{
name = i.name
expires = i.expires -1
value = i.value -10
} |> BarItem
| // etc
想想 C# 程序中实际发生了什么。
您有多个不同的 handleDevalue
实现,每个项目实例都有其中一个与之关联的实现。但是,是什么决定了哪个与哪个项目相配呢?好吧,这是由该项目的特定后代 class 决定的。好的,但是什么决定了实例化哪个后代 class?
某个地方,某个时间点,一定有一个地方以某种方式挑选后代class。让我们假设它看起来像这样:
class Item { public abstract int handleDevalue() { ... } }
class FooItem : Item { public override int handleDevalue() { ... } }
class BarItem : Item { public override int handleDevalue() { ... } }
public Item createItem(string name, Days expires, Value value) {
if (foo) return new FooItem(name, expires, value)
else return BarItem(name, expires, value)
}
所以,看看发生了什么:最终,创建项目的人正在选择最终使用哪个 handleDevalue
实现,然后该实现附加到项目通过 table.
现在我们知道了这一点,我们可以在 F# 中做同样的事情。我们只需要明确附加实现即可:
type Item = {
Name : string
Expires : Days
Value : Value
handleDevalue : Item -> Item
}
let handleDevalueFoo item = ...
let handleDevalueBar item = ...
let createItem name expires value = {
Name = name
Expires = expires
Value = value
handleDevalue = if foo then handleDevalueFoo else handleDevalueBar
}