2013-08-08 9 views
7

Chcę napisać równowartość tej C# w F #:Jak zadeklarować niezmienny struct z polami publicznymi?

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

Zmusza to użytkownika do dostarczyć argumentów do utworzenia instancji [EDIT: to jest złe dla typów wartości - wszystkie typy wartości mają domyślnego konstruktora] . Domyślny Vector2 może być również wyposażony w statyczne pole tylko do odczytu, tj. Vector2.Zero.

Wygląda na to, że jedynym sposobem uzyskania pól publicznych jest słowo kluczowe "val", ale nie pozwala mi na zainicjowanie ich za pomocą domyślnego konstruktora, a nie chcę mieć dwóch konstruktorów:

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

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

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

Wiem, że można to zrobić z powiązaniami członków, ale to tworzy właściwości, a nie pola, jeśli dobrze rozumiem.

Odpowiedz

5

Według tego http://msdn.microsoft.com/en-us/library/vstudio/dd233233(v=vs.120).aspx, które mogą być wykonane jako

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

Niestety, pozwala mi to utworzyć wektor bez przekazywania parametrów, jak na przykład: 'let v = Vector2()'. Nie chodzi o to, że jest to bardzo poważny problem, ale wciąż zastanawiam się, czy można to zrobić bez domyślnego pustego konstruktora. – Asik

+5

@Asik: To samo dotyczy kodu C# - jest to ograniczenie CLR, a nie ograniczenie F #. – ildjarn

+1

"Struktury nie mogą mieć konstruktora obiektu bez argumentów, jest to ograniczenie nałożone na wszystkie języki interfejsu CLI, ponieważ struktury automatycznie obsługują domyślny konstruktor." - tak mówi kompilator, więc nie zawsze możesz dostać to, czego chcesz ... –

2

Jeśli F # Record będzie pracować dla Ciebie, to będzie działać:

type MyInt = { 
    Value: int 
};; 

Następnie zainicjować:

let i = {Value=1};; 

Ponieważ nie jestem całkowicie pewien twojego przypadku użycia, nie jestem pewien, jak pomocne jest to jest.

EDIT: Na co warto, jeśli powodem preferując typ wartości jest to, że chcesz typ wartości semantykę równości, zapisy potwierdzają, że (mimo że są typy referencyjne). Rozważ to:

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 

Chcę powiedzieć, że choć rekordy są typy referencyjne, jednym z powodów, że ludzie używają typy wartości (semantyka równości) nie ma problemu z ewidencji. Mimo że jest to typ odniesienia, uważam, że jest on dużo bliższy zachowaniu kodu C#, który próbujesz naśladować - za to, co jest warte.

+0

Problem z rekordami polega na tym, że są one implementowane jako typy odniesienia z właściwościami i tutaj próbuję uzyskać typ wartości z polami. – Asik

+0

Znowu - nie znasz swojego przypadku użycia, ale mimo że rekordy są typami referencyjnymi, mają semantykę równości typu wartości. Zmieniłem moją odpowiedź, aby wyjaśnić to nieco dalej. –

+0

Naprawdę nie mam przypadku użycia, próbowałem po prostu zrozumieć, jak utworzyć typ wartości z publicznymi niezmiennymi polami (w sensie CLR) i unikać domyślnego konstruktora. Dziękuję za wyjaśnienia. – Asik

Powiązane problemy