2011-12-21 16 views
13

Các mục trong bộ dữ liệu không có tên, có nghĩa là bạn thường không có cách rõ ràng để ghi lại ý nghĩa của từng mục.Thực tiễn tiêu chuẩn có sử dụng bí danh loại để chỉ ra ngữ nghĩa tham số không?

Ví dụ, trong này phân biệt đối xử công đoàn:

type NetworkEvent = 
| Message of string * string * string 
| ... 

tôi muốn làm cho nó rõ ràng rằng mục đầu tiên và thứ hai là những người gửi và tên người nhận tương ứng. Là nó thực hành tốt để làm một cái gì đó như thế này:

type SenderName = string 
type RecipientName = string 

type NetworkEvent = 
| Message of SenderName * RecipientName * string 
| ... 

Rất nhiều ++ thư viện C/C có một sự gia tăng của các loại (ví dụ win32.h), nhưng trong những ngôn ngữ, mặc dù tên tham số là tùy chọn trong nhiều trường hợp , nó vẫn có thể được thực hiện. Đó không phải là trường hợp với F #.

+3

Trong F # 3.1, chúng có thể có tên. –

+0

@ JamesMoore Vâng, điều đó làm tôi hạnh phúc: D –

Trả lời

10

Tôi nghĩ rằng việc sử dụng bí danh kiểu cho mục đích tài liệu là một cách tốt và đơn giản để ghi lại các đoàn thể kỳ thị của bạn.Tôi sử dụng cách tiếp cận tương tự trong nhiều bản trình diễn của tôi (xem for example this one) và tôi biết rằng một số người cũng sử dụng nó trong các ứng dụng sản xuất. Tôi nghĩ có hai cách để làm cho định nghĩa tự giải thích hơn:

Sử dụng bí danh loại: Bằng cách này, bạn thêm một số tài liệu có thể nhìn thấy trong IntelliSense, nhưng nó không lan truyền qua hệ thống kiểu - khi bạn sử dụng giá trị của loại bí danh, trình biên dịch sẽ coi nó là string, vì vậy bạn không thấy tài liệu bổ sung ở mọi nơi.

Sử dụng các trường hợp đơn lẻ Đây là mẫu được sử dụng ở một số nơi của trình biên dịch F #. Nó làm cho thông tin hơn có thể nhìn thấy vì sử dụng kiểu bí danh, vì một loại SenderName thực sự là một loại khác với string (mặt khác, điều này có thể có một số hình phạt hiệu suất nhỏ):

type SenderName = SenderName of string 
type RecipientName = RecipientName of string 
type NetworkElement = 
    | Message of SenderName * RecipietName * string 

match netelem with 
| Message(SenderName sender, RecipientName recipiet, msg) -> ... 

Sử dụng hồ sơ: Bằng cách này, bạn xác định rõ ràng một bản ghi để mang thông tin của một trường hợp công đoàn. Điều này có tính chi tiết hơn về cú pháp, nhưng nó có thể thêm thông tin bổ sung theo cách dễ tiếp cận nhất. Bạn vẫn có thể sử dụng đối sánh mẫu trên bản ghi hoặc bạn có thể sử dụng ký hiệu dấu chấm để truy cập các phần tử. Việc thêm các trường mới trong quá trình phát triển cũng dễ dàng hơn:

type MessageData = 
    { SenderName : string; RecipientName : string; Message : string } 
type NetworkEvent = 
    | Message of MessageData 

match netelem with 
| Message{ SenderName = sender; RecipientName = recipiet; Message = msg} -> ... 
+3

Dựa trên số phiếu bầu, đây có lẽ là quan điểm thiểu số, nhưng độ dài của các hồ sơ hoặc các trường hợp đơn lẻ là một thỏa thuận ngắt trong lí trí. Nó hoàn toàn phủ nhận sự tiện lợi/cú pháp của các công đoàn. Điều này có vẻ như một vấn đề được giải quyết tốt nhất bởi Intellisense - miễn là có cách chú thích các trường - không thay đổi kiểu và kiểu mã hóa của bạn. – Daniel

+1

Tôi nghĩ câu trả lời này (nếu không xuất sắc) có thể cần cập nhật. Bây giờ bạn có thể thực hiện 'type X = Msg of Sender: string * Recip: string'. Và bạn cũng có thể sử dụng các trường này: 'let x = X (Tên người gửi =" Foo ", Recip =" Bar ")'. Cũng giống như các bản ghi, nhưng với cú pháp khác nhau. – Abel

1

Tôi nghĩ Trong trường hợp này, bạn nên sử dụng loại bản ghi cho hai phần tử đầu tiên của bộ dữ liệu để củng cố thực tế là thứ tự quan trọng.

Đối với con số này, bạn có thể làm điều gì đó một chút thanh lịch hơn sử dụng đơn vị đo lường, nhưng điều này không làm việc cho chuỗi

+0

Sẽ không một sự gia tăng của các hồ sơ được chỉ là xấu - nếu không tồi tệ hơn, nếu có rất nhiều 'NetworkEvents'? Các suy luận loại được thực sự bối rối khi có tấn hồ sơ với tên tham số tương tự, và bạn sẽ phải hoàn toàn đủ điều kiện mỗi lĩnh vực duy nhất. –

+0

@ReiMiyasaka - thực sự tình hình không phải là khá xấu. Nếu bạn hoàn toàn đủ điều kiện trường đầu tiên mà bạn đề cập khi tạo bản ghi, những người khác sẽ giải quyết chính xác. – Kit

1

tôi không thấy bất cứ điều gì sai với điều này, nhưng nó có thể được gây phiền nhiễu có 10 bí danh cho Ví dụ: string. Nếu điều đó không làm phiền bạn, tôi nói, đi trước. Cá nhân, tôi muốn một cái gì đó như sau được hỗ trợ:

type NetworkEvent = 
| Message of SenderName:string * RecipientName:string * string 
| ... 

Sau đó, Intellisense có thể cung cấp một số trợ giúp. (EDIT: Bỏ phiếu cho đề xuất này here.)

Nếu trường hợp của bạn có nhiều trường hoặc nhiều loại cùng loại, bạn có thể cân nhắc sử dụng phân cấp lớp thay thế.

+0

Vâng, có rất nhiều khía cạnh của cú pháp F # mà chỉ làm cho nó không thể có một IntelliSense phong phú như C#. –

+0

Có một cải tiến gần đây cho phép điều này - "Theo F # 3.1, bạn có thể đặt tên cho một trường riêng lẻ, nhưng tên là tùy chọn, ngay cả khi các trường khác trong cùng một trường hợp được đặt tên." http://msdn.microsoft.com/en-us/library/dd233226.aspx –

6

Tôi đã đọc phần chia sẻ vé F #, cả trên internet và sách nhưng chưa bao giờ thấy bất kỳ ai sử dụng bí danh dưới dạng tài liệu. Vì vậy, tôi sẽ nói đó không phải là thực hành tiêu chuẩn. Nó cũng có thể được xem như một dạng sao chép mã.

Nói chung, biểu diễn tuple cụ thể chỉ nên được sử dụng làm cấu trúc dữ liệu tạm thời trong một hàm. Nếu bạn đang lưu trữ một tuple trong một thời gian dài hoặc chuyển nó giữa các lớp khác nhau, thì đã đến lúc tạo một bản ghi.

Nếu bạn định sử dụng một công đoàn phân biệt đối xử trên nhiều lớp, hãy sử dụng các bản ghi như bạn đã đề xuất hoặc giữ tất cả các phương pháp được dàn xếp cho công đoàn phân biệt như dưới đây.

type NetworkEvent = 
    | Message of string * string * string 

    static member Create(sender, recipient, message) = 
     Message(sender, recipient, message) 

    member this.Send() = 
     math this with 
     | Message(sender, recipient, message) -> 
      printf "Sent: %A" message 

let message = NetworkEvent.Create("me", "you", "hi") 

Bạn có thể sử dụng records in pattern matching, vì vậy bộ dữ liệu thực sự là vấn đề thuận tiện và cần được thay thế bằng các bản ghi khi mã tăng lên.

Nếu một công đoàn bị phân biệt đối xử có một loạt các bộ dữ liệu có chữ ký giống nhau thì đã đến lúc chia thành hai công đoàn phân biệt đối xử. Điều này cũng sẽ ngăn không cho bạn có nhiều bản ghi có cùng chữ ký.

type NetworkEvent2 = 
    | UDPMessage of string * string * string 
    | Broadcast of string * string * string 
    | Loopback of string * string * string 
    | ConnectionRequest of string 
    | FlushEventQueue 

vào

type MessageType = 
    | UDPMessage 
    | Broadcast 
    | Loopback 

type NetworkEvent = 
    | Message of MessageType * string * string * string 
    | ConnectionRequest of string 
    | FlushEventQueue 
Các vấn đề liên quan