F # имеет множество различных способов определения переменных/членов в типах. Когда следует использовать let
, member val
и member this.
в F #, и в чем разница между ними? Как насчет статических и изменяемых элементов?
Когда следует использовать let, member val и member this.?
Ответ 1
Ответ от @meziantou уже дает хороший обзор вариантов (и как они ведут себя по-другому), поэтому позвольте мне просто дать краткий обзор или список рекомендаций:
-
Используйте
let
илиlet mutable
, если вы хотите определить локальное значение, которое отображается только внутри типа (по существу, это полеprivate
или функцияprivate
). -
Вы можете использовать
val
илиval mutable
для определения открытого поля, но я бы не рекомендовал это, если вам действительно не нужно публичное поле (например, для некоторой библиотеки .NET требуется тип с этой структурой). -
Использование
member x.Foo = ...
- лучший способ открыть (только для чтения) состояние из типа. Большинство типов F # неизменяемы, поэтому это, пожалуй, самый общий публичный элемент. -
Использование
member x.Foo with get() = .. and set(value) ...
полезно, когда вам нужно создать свойство get/set со своим собственным кодом в getter и setter. Иногда это полезно, когда вы создаете изменяемый объект. -
Использование
member val Foo = ... with get, set
- это в основном то же самое, что и автоматически реализованные свойства в С#. Это полезно, если вам нужно свойство mutable с getter и setter, которые просто читают/записывают изменяемое поле поддержки.
Ответ 2
Мне стало проще просто декомпилировать, что происходит, поэтому:
type Region() =
let mutable t = 0.0f
member val Width = 0.0f
member x.Height = 0.0f
member val Left = 0.0f with get,set
member x.Top with get() = 0.0f and set(value) = t <- value
на самом деле следующее:
public class Region
{
internal float t;
internal float [email protected];
internal float [email protected];
public float Width
{
get
{
return [email protected];
}
}
public float Height
{
get
{
return 0f;
}
}
public float Left
{
get
{
return [email protected];
}
set
{
[email protected] = value;
}
}
public float Top
{
get
{
return 0f;
}
set
{
this.t = value;
}
}
public Region() : this()
{
this.t = 0f;
[email protected] = 0f;
[email protected] = 0f;
}
}
Ответ 3
Этот пример объясняет разницу между синтаксисами:
type MyClass() =
let random = new System.Random()
[<DefaultValue>] val mutable field : int
member val AutoProperty = random.Next() with get, set
member this.ExplicitProperty = random.Next()
let c = new MyClass()
// c.random is not accessible
c.field <- 42 // 'field' is accessible
// An automatic property is only evaluated upon initialization, and not every time the property is accessed
printfn "AutoProperty = %d" c.AutoProperty // x
printfn "AutoProperty = %d" c.AutoProperty // Still x
// The value of the explicit property is evaluated each time
printfn "ExplicitProperty = %d" c.ExplicitProperty // y
printfn "ExplicitProperty = %d" c.ExplicitProperty // The value is re-evaluated so you'll get a different value