2015-12-10 7 views
6

मैं की तरहप्रकार एक स्ट्रिंग जो खाली या एफ # में रिक्त स्थान

type Code = Code of string 

प्रकार की सादगी प्यार लेकिन मैं (स्ट्रिंग पर कुछ प्रतिबंध लगाने के लिए इस मामले में चाहते हैं नहीं है प्रतिनिधित्व करने के लिए - के खाली की अनुमति नहीं है रिक्त स्थान केवल तार)।

type nonemptystring = ??? 
type Code = Code of nonemptystring 

मैं इस प्रकार को F # idiomatic तरीके से कैसे परिभाषित करूं? मुझे पता है कि मैं इसे कारखाने के समारोह के साथ निर्माता या प्रतिबंधित मॉड्यूल के साथ एक वर्ग बना सकता हूं, लेकिन क्या कोई आसान तरीका है?

+3

इस पोस्ट पर एक नज़र डालें: http://fsharpforfunandprofit.com/posts/designing-with-types-more-semantic-types/ - अनुभाग "मॉडलिंग प्रकारों के साथ स्ट्रिंग बाध्य"। आपको शायद इस – Petr

+0

@Petr जैसे कुछ ऐसा करने की आवश्यकता होगी मैंने इस पोस्ट को देखा लेकिन मुझे यह समाधान कुछ हद तक जटिल लगता है। वैसे भी लिंक के लिए धन्यवाद। – Mikhail

+0

हां, मैं मानता हूं कि वह पोस्ट थोड़ा जटिल है। मेरे यहां कुछ बेहतर उदाहरण हैं: https://gist.github.com/swlaschin/54cfff886669ccab895a। जैसा कि अन्य ने बताया है, समाधान विशेष रूप से सुरुचिपूर्ण नहीं हैं। ओटीओएच, आपको ओओ कोड में भी कुछ ऐसा करना होगा। – Grundoon

उत्तर

0

दुर्भाग्य से प्रकारों के प्रतिबंधित सबसेट घोषित करने के लिए सुविधाजनक वाक्यविन्यास नहीं है लेकिन मैं ऐसा करने के लिए सक्रिय पैटर्न का लाभ उठाऊंगा। आप ठीक ही कहते हैं कि रूप में, आप एक प्रकार बनाने के लिए और यह वैधता जब आप इसे का निर्माण है की जाँच कर सकते हैं:

/// String type which can't be null or whitespace 
type FullString (string) = 
    let string = 
     match (System.String.IsNullOrWhiteSpace string) with 
     |true -> invalidArg "string" "string cannot be null or whitespace" 
     |false -> string 
    member this.String = string 

अब, इस प्रकार के भोलेपन से निर्माण क्रम अपवाद फेंक कर सकते हैं और हम चाहते हैं कि नहीं चाहता! तो चलो सक्रिय पैटर्न का उपयोग करते हैं:

let (|FullStr|WhitespaceStr|NullStr|) (str : string) = 
    match str with 
    |null -> NullStr 
    |str when System.String.IsNullOrWhiteSpace str -> WhitespaceStr 
    |str -> FullStr(FullString(str)) 

अब हम कुछ है कि हम पैटर्न मिलान वाक्य रचना के साथ उपयोग कर सकते हैं हमारे FullString रों का निर्माण करने के लिए है। यह फ़ंक्शन रनटाइम पर सुरक्षित है क्योंकि हम केवल FullString बनाते हैं यदि हम वैध मामले में हैं।

आप इस तरह इसका इस्तेमाल कर सकते हैं:

let printString str = 
    match str with 
    |NullStr -> printfn "The string is null" 
    |WhitespaceStr -> printfn "The string is whitespace" 
    |FullStr fstr -> printfn "The string is %s" (fstr.String) 
+0

इस उदाहरण के लिए धन्यवाद। मेरे पास दो चिंताओं हैं: 1. हर बार जब मैं इसे कहीं भी अजीब लग रहा हूं, तो मुझे ".Sring" का उपयोग करना होगा। 2. मुझे बराबर ओवरराइड करना होगा और इस फुलस्ट्रिंग प्रकार के लिए क्या नहीं होगा। – Mikhail

+0

@ मिखाइल आप एक कक्षा के बजाय एक रिकॉर्ड का उपयोग कर सकते हैं जो आपको स्वचालित संरचनात्मक तुलना, समानता इत्यादि देगा, लेकिन आपको यह सुनिश्चित करने के लिए थोड़ा और चाल चलाना होगा कि रिकॉर्ड में कभी भी अमान्य स्ट्रिंग नहीं हो सकती है। उस ने कहा, ये ओवरराइड बहुत सरल होना चाहिए क्योंकि आप सीधे स्ट्रिंग के तरीकों पर रीडायरेक्ट कर सकते हैं। – TheInnerLight

3

एक string अनिवार्य रूप से char मूल्यों का एक क्रम है (हास्केल में, Btw, String[Char] के लिए एक प्रकार का अन्य नाम है)। एक और सामान्य सवाल, तब होगा, यदि किसी दिए गए आकार के रूप में एक सूची घोषित करना संभव है।

ऐसी भाषा सुविधा Dependent Types के रूप में जानी जाती है, और F # में यह नहीं है। इसलिए, संक्षिप्त जवाब यह है कि घोषणात्मक फैशन में ऐसा करना संभव नहीं है।

सबसे आसान है, और शायद यह भी सबसे मुहावरेदार, जिस तरह से है, तो, एक एकल मामले भेदभाव संघ के रूप में Code परिभाषित करने के लिए किया जाएगा:

type Code = Code of string 

मॉड्यूल Code को परिभाषित करता है, आप यह भी निर्धारित करेंगे एक समारोह ग्राहकों Code मान बनाने के लिए उपयोग कर सकते हैं कि:

let tryCreateCode candidate = 
    if System.String.IsNullOrWhiteSpace candidate 
    then None 
    else Some (Code candidate) 

इस समारोह रन-टाइम तर्क है कि खाली Code मूल्यों का निर्माण करने से ग्राहकों को रोकता है:

> tryCreateCode "foo";; 
val it : Code option = Some (Code "foo") 
> tryCreateCode "";; 
val it : Code option = None 
> tryCreateCode " ";; 
val it : Code option = None 

क्या ग्राहक को अमान्य Code मान बनाने से रोकता है, तो? उदाहरण के लिए, क्या कोई ग्राहक tryCreateCode फ़ंक्शन को बाधित करने में सक्षम नहीं होगा और बस Code "" लिखें?

यह वह जगह है जहां signature files आते हैं।आप एक हस्ताक्षर फ़ाइल (.fsi) बनाते हैं, और है कि में इस तरह के प्रकार और कार्यों की घोषणा:

type Code 
val tryCreateCode : string -> Code option 

यहाँ, Code प्रकार घोषित किया जाता है, लेकिन इसके 'निर्माता' नहीं है। इसका मतलब है कि आप सीधे इस प्रकार के मान नहीं बना सकते हैं। यह, उदाहरण के लिए, संकलन नहीं करता है:

Code "" 

दिया त्रुटि है:

त्रुटि FS0039: मूल्य, निर्माता, नाम स्थान या प्रकार 'कोड'

परिभाषित नहीं है

Code मान बनाने का एकमात्र तरीका tryCreateCode फ़ंक्शन का उपयोग करना है।

के रूप में यहाँ दी, आप अब Code की अंतर्निहित स्ट्रिंग मान, उपयोग कर सकते हैं जब तक आप भी उस के लिए एक समारोह प्रदान करते हैं:

let toString (Code x) = x 

और एक ही .fsi फ़ाइल में के रूप में ऊपर की घोषणा:

val toString : Code -> string 

यह बहुत काम की तरह दिख सकता है, लेकिन वास्तव में केवल छह पंक्तियों की कोड है, और तीन प्रकार की घोषणा (.fsi फ़ाइल में) है।

+1

प्रकार कन्स्ट्रक्टर निजी विकल्प नहीं बनायेगा? 'टाइप कोड = स्ट्रिंग का निजी कोड' –

+0

@ निकोसबैक्सवेनिस मुझे नहीं पता था कि आप ऐसा कर सकते हैं: $ धन्यवाद! वह '.fsi' फ़ाइल की आवश्यकता के साथ विवाद करता है, लेकिन मेरा बाकी का उत्तर अभी भी लागू होता है। –

संबंधित मुद्दे