2013-08-08 3 views
7

Я хочу написать эквивалент этой C# в F #:Как объявить неизменяемую структуру с открытыми полями?

struct Vector2 { 
    public readonly int X; 
    public readonly int Y; 
    public Vector2(int x, int y) { 
     X = x; 
     Y = y; 
    } 
} 

Это заставляет пользователя предоставить аргументы для создания экземпляра [EDIT: это неправильно для типов значений - все типы значений иметь конструктор по умолчанию] , Вектор Vector по умолчанию также может быть снабжен статическим полем readonly, то есть Vector2.Zero.

Похоже, что единственный способ получить открытые поля осуществляется с помощью ключевого слова «ВАЛ», но, кажется, не дайте мне инициализировать их с конструктором по умолчанию, и я не хочу иметь два конструктора:

[<Struct>] 
    type MyInt(value) = 
     val public Value : int = value;; 

      val public Value : int = value;; 
    -------------------------------^ 

stdin(7,32): error FS0010: Unexpected symbol '=' in member definition 

Я знаю, что это можно сделать с привязками элементов, но это создает свойства, а не поля, если я хорошо понимаю.

ответ

5

Согласно этому http://msdn.microsoft.com/en-us/library/vstudio/dd233233(v=vs.120).aspx, что может быть сделано как

type Vector2 = 
    struct 
     val public X: int 
     val public Y: int 
     new(x: int, y: int) = { X = x; Y = y } 
    end 
+0

К сожалению, это позволяет мне создать вектор без параметров, например: 'let v = Vector2()'. Не то, чтобы это очень серьезная проблема, но мне все еще интересно, можно ли это сделать без использования пустого конструктора по умолчанию. – Asik

+5

@Asik: То же самое относится к вашему C# -коду - это ограничение CLR, а не ограничение F #. – ildjarn

+1

«Структуры не могут иметь конструктора объектов без аргументов. Это ограничение, наложенное на все языки CLI, поскольку структуры автоматически поддерживают конструктор по умолчанию». - это то, что компилятор говорит, поэтому вы не всегда можете получить то, что хотите ... –

2

Если F # Record будет работать для вас, то это будет работать:

type MyInt = { 
    Value: int 
};; 

Тогда для инициализации:

let i = {Value=1};; 

Поскольку я не совсем уверен в вашем случае использования, я не уверен, насколько это полезно является.

EDIT: Для чего стоит, если ваша причина для предпочтения типа значения заключается в том, что вы хотите семантику равенства типа значения, записи поддерживают это (хотя они и являются ссылочными типами). Рассмотрим это:

type Vector2 = { 
    X:int; 
    Y:int 
};; 

type Vector2 = 
    {X: int; 
    Y: int;} 

let v = {X=1;Y=1};; 

val v : Vector2 = {X = 1; 
        Y = 1;} 

let v2 = {X=1;Y=1};; 

val v2 : Vector2 = {X = 1; 
        Y = 1;} 

v = v2;; 
val it : bool = true 

let v3 = {X=2;Y=2};; 
v = v3;; 
val it: bool = false 

Я хочу сказать, что даже если записи являются ссылочными типами, одна из причин того, что люди используют типы значений (семантика равенства) не является проблемой, с записями. Несмотря на то, что это ссылочный тип, я считаю, что он намного ближе к поведению кода C#, который вы пытаетесь подражать, - для чего он стоит.

+0

Проблема с записями заключается в том, что они реализованы как ссылочные типы со свойствами, и здесь я пытаюсь получить тип значения с полями. – Asik

+0

Опять же - не знаю ваш вариант использования, но даже если записи являются ссылочными типами, они имеют семантику равенства типа значения. Я отредактировал свой ответ, чтобы объяснить его немного дальше. –

+0

У меня на самом деле нет прецедента, я просто пытался понять, как создать тип значения с общедоступными неизменяемыми полями (в смысле CLR) и избежать создания конструктора по умолчанию. Спасибо за ваши объяснения. – Asik