2012-01-11 26 views
7

Vì vậy, đã nhận được để ghi lại trong hành trình F # của tôi và lúc đầu họ có vẻ khá nguy hiểm. Lúc đầu, điều này có vẻ thông minh:Bản ghi F #: Nguy hiểm, chỉ để sử dụng hạn chế hoặc chức năng được sử dụng tốt?

type Card = { Name : string; 
      Phone : string; 
      Ok : bool } 

let cardA = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 

Ý tưởng rằng thẻA là patten khớp với Thẻ. Chưa kể đến mô hình đơn giản phù hợp ở đây:

let withTrueOk = 
    list 
    |> Seq.filter 
    (function 
     | { Ok = true} -> true 
     | _ -> false 
) 

Vấn đề là:

type Card = { Name : string; 
      Phone : string; 
      Ok : bool } 

type CardTwo = { Name : string; 
      Phone : string; 
      Ok : bool } 

let cardA = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 

cardA bây giờ là loại CardTwo mà tôi đoán đã làm với F # chạy tất cả mọi thứ theo thứ tự.

Bây giờ điều này có thể là một tình huống không thể vì có thể không bao giờ có cơ hội có cùng chữ ký nhận hai loại, nhưng đó là một khả năng.

Đang ghi lại nội dung nào đó chỉ bị giới hạn sử dụng hoặc tôi chỉ nghĩ về điều này?

+8

Bạn đang ghi đè nó - cung cấp cho các yếu tố hồ sơ của bạn để so khớp/khởi tạo ví dụ 'let cardA = {Card.Name =" Alf "; Điện thoại = "(206) 555-0157"; Ok = false} '. – ildjarn

+14

IMHO mutability theo mặc định, thừa kế và thiếu bình đẳng cấu trúc làm cho lớp học nguy hiểm hơn hồ sơ, nhưng bạn không thấy nhiều người phàn nàn về điều đó ;-) –

+7

@MauricioScheffer Thêm vào đó nullability theo mặc định. –

Trả lời

18

Chúng không nguy hiểm và chúng không chỉ dành cho mục đích sử dụng hạn chế.

Tôi nghĩ rất hiếm khi bạn có hai loại với cùng thành viên. Nhưng nếu bạn gặp phải tình huống đó, bạn có thể đủ điều kiện loại bản ghi mà bạn muốn sử dụng:

let cardA = { Card.Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 

Ghi lại rất hữu ích cho việc tạo (hầu hết) cấu trúc dữ liệu không thay đổi. Và thực tế là bạn có thể dễ dàng tạo ra một bản sao chỉ với một số lĩnh vực đã thay đổi là rất tốt quá:

let cardB = { cardA with Ok = true } 
12

Tôi đồng ý, lĩnh vực kỷ lục là thành viên của kèm theo mô-đun/namespace có vẻ kỳ lạ lúc đầu đến từ nhiều ngôn ngữ OO truyền thống. Nhưng F # cung cấp một số lượng khá linh hoạt ở đây. Tôi nghĩ rằng bạn sẽ tìm thấy chỉ tình huống giả tạo gây ra vấn đề, chẳng hạn như hai hồ sơ mà

  1. là giống hệt nhau
  2. có mối quan hệ tập hợp con/superset

Các trường hợp đầu tiên không bao giờ nên xảy ra. Loại sau có thể được giải quyết bằng cách ghi lại B có trường ghi là A.

Bạn chỉ cần một trường khác nhau để hai trường có thể phân biệt được. Ngoài ra, các định nghĩa có thể giống nhau.

type Card = 
    { Name : string 
    Phone: string 
    Ok : bool } 

type CardTwo = 
    { Name : string 
    Phone: string 
    Age : int } 

let card = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 
let cardTwo = { Name = "Alf" ; Phone = "(206) 555-0157" ; Age = 21 } 

So khớp mẫu cũng khá linh hoạt vì bạn chỉ cần khớp trên đủ trường để phân biệt với các loại khác.

let readCard card = 
    match card with 
    | { Ok = false } ->() //OK 
    | { Age = 21 } ->() //ERROR: 'card' already inferred as Card, but pattern implies CardTwo 

Ngẫu nhiên, kịch bản của bạn được dễ dàng cố định với một loại chú thích:

let cardA : Card = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 
+0

Tại sao mối quan hệ tập hợp con/superset lại là một vấn đề? AFAIK, bạn phải luôn luôn chỉ định tất cả các thuộc tính. – svick

+2

Khi đối sánh mẫu. Bạn chỉ phải đối sánh trên các trường đủ để phân biệt với các loại bản ghi khác. Kiểm tra mã của tôi. – Daniel

6

Trong thứ tự mà bạn đánh giá cao những gì F # cung cấp, tôi chỉ muốn đề cập đến là không có accessor đầy đủ cho các bản ghi trong OCaml.Do đó, để phân biệt giữa các loại bản ghi với các trường giống nhau, bạn phải đặt chúng vào các mô-đun con và tham khảo chúng bằng cách sử dụng các tiền tố mô-đun.

Vì vậy, tình huống của bạn trong F # tốt hơn nhiều. Bất kỳ sự nhập nhằng giữa các loại kỷ lục tương tự có thể được giải quyết một cách nhanh chóng bằng kỷ lục accessor:

type Card = { Name: string; 
      Phone: string; 
      Ok: bool } 

type CardSmall = { Address: string; 
      Ok: bool } 

let withTrueOk list = 
    list 
    |> Seq.filter (function 
       | { Card.Ok = true} -> true (* ambiguity could happen here *) 
       | _ -> false) 

Hơn nữa, F # kỷ lục không chỉ giới hạn ở tất cả. Nó cung cấp rất nhiều tính năng tuyệt vời ngoài tính năng kết hợp mẫu, tính bất biến mặc định, tính bình đẳng về cấu trúc, v.v.

+9

Nếu bạn xác định hai loại bản ghi với cùng các trường, bạn có thể ngăn truy cập không đủ điều kiện (và sự mơ hồ vốn có) bằng cách chú thích các loại của bạn bằng '[]'. – Daniel

+0

@Daniel: Rất hay. – pad

Các vấn đề liên quan