2014-06-10 6 views
15

मैं सामान्य पुस्तक के लिए स्विफ्ट पुस्तक से मैट्रिक्स उदाहरण पोर्ट करने की कोशिश कर रहा हूं।स्विफ्ट में कोई डिफ़ॉल्ट (टी) नहीं है?

यहाँ मैं अब तक क्या मिला है:

struct Matrix<T> { 
    let rows: Int, columns: Int 
    var grid: T[] 

    init(rows: Int, columns: Int, repeatedValue: T) { 
     self.rows = rows 
     self.columns = columns 

     grid = Array(count: rows * columns, repeatedValue: repeatedValue) 
    } 

    func indexIsValidForRow(row: Int, column: Int) -> Bool { 
     return row >= 0 && row < rows && column >= 0 && column < columns 
    } 

    subscript(row: Int, column: Int) -> T { 
     get { 
      assert(indexIsValidForRow(row, column: column), "Index out of range") 
      return grid[(row * columns) + column] 
     } 
     set { 
      assert(indexIsValidForRow(row, column: column), "Index out of range") 
      grid[(row * columns) + column] = newValue 
     } 
    } 
} 

ध्यान दें कि मैं था निर्माता को repeatedValue: T पारित करने के लिए।

सी # में, मैं सिर्फ default(T) इस्तेमाल किया है | जो संदर्भ प्रकार के लिए बूलियन्स के लिए संख्या के लिए 0, false और null होगा। मैं समझता हूं कि स्विफ्ट गैर-वैकल्पिक प्रकारों पर nil की अनुमति नहीं देता है, लेकिन अगर मैं एक स्पष्ट पैरामीटर पास कर रहा हूं, तो मैं अभी भी उत्सुक हूं, या अगर default(T) के बराबर है।

उत्तर

6

ऐसा नहीं है। स्विफ्ट आपको डिफ़ॉल्ट मान निर्दिष्ट करने के लिए मजबूर करता है, जैसे कि आप चर और फ़ील्ड को संभालते हैं। एकमात्र मामला जहां स्विफ्ट में डिफ़ॉल्ट मान की अवधारणा है, वैकल्पिक प्रकारों के लिए है, जहां यह nil (Optional.None) है।

3

एक iffy 'हाँ'। आप आवश्यकता को निर्दिष्ट करने के लिए प्रोटोकॉल बाधाओं का उपयोग कर सकते हैं कि आपकी जेनेरिक क्लास या फ़ंक्शन केवल उन प्रकारों के साथ काम करेगा जो डिफ़ॉल्ट init फ़ंक्शन (पैरामीटर-कम) को लागू करते हैं। इसकी रैमिकेशंस सबसे अधिक खराब होगी (यह आपके द्वारा किए जाने वाले तरीके से काम नहीं करती है), लेकिन यह 'निकट' उत्तर से कहीं अधिक निकटतम चीज़ है, जो आप पूछ रहे थे।

मेरे लिए मुझे यह एक व्यक्तिगत जेनेरिक वर्ग के विकास के दौरान व्यक्तिगत रूप से मददगार पाया गया, और अंततः मैं बाधा को हटा देता हूं और शेष मुद्दों को ठीक करता हूं। केवल डिफ़ॉल्ट प्रकार पर लगने वाले प्रकारों की आवश्यकता आपके सामान्य डेटा प्रकार की उपयोगिता को सीमित कर देगी।

public protocol Defaultable 
{ 
    init() 
} 

struct Matrix<Type: Defaultable> 
{ 
    let rows: Int 
    let columns: Int 
    var grid: [Type] 

    init(rows: Int, columns: Int) 
    { 
    self.rows = rows 
    self.columns = columns 

    grid = Array(count: rows * columns, repeatedValue: Type()) 
    } 
} 
2

वहाँ एक तरह से तेजी में default(T) के बराबर लाने के लिए है, लेकिन यह मुक्त नहीं है और यह एक संबद्ध खतरा है:

public func defaultValue<T>() -> T { 
    let ptr = UnsafeMutablePointer<T>.alloc(1) 
    let retval = ptr.memory 
    ptr.dealloc(1) 
    return retval; 
} 

यह स्पष्ट रूप से एक हैक क्योंकि हम नहीं जानते कि है अब अगर alloc() कुछ जानकारियों को शुरू करता है। क्या यह सब 0 है? ढेर में सामग्री छोड़ दिया? कौन जानता है? इसके अलावा, आज क्या हो सकता है कल कुछ अलग हो सकता है।

वास्तव में, के लिए वापसी मूल्य का उपयोग प्लेसहोल्डर के अलावा कुछ भी खतरनाक है। मान लें कि आप इस तरह कोड करते हैं:

public class Foo { /* implementation */ 
public struct Bar { public var x:Foo } 
var t = defaultValue<Bar>(); 
t = someFactoryThatReturnsBar(); // here's our problem 

समस्या लाइन में स्विफ्ट का मानना ​​है कि t क्योंकि स्विफ्ट का अर्थ विज्ञान क्या कहते है कि प्रारंभ कर दिया गया है आप एक मान प्रकार है कि अप्रारंभीकृत है के एक चर नहीं हो सकता। सिवाय इसके कि ऐसा इसलिए है क्योंकि default<T> उन अर्थशास्त्र को तोड़ देता है। जब आप असाइनमेंट करते हैं, स्विफ्ट मौजूदा प्रकार को नष्ट करने के लिए मूल्य गवाह तालिका में कॉल को उत्सर्जित करता है। इसमें कोड शामिल होगा जो release को x पर कॉल करेगा, क्योंकि स्विफ्ट अर्थशास्त्र का कहना है कि वस्तुओं के उदाहरण कभी भी nil नहीं हैं। और फिर आपको रनटाइम क्रैश मिलता है।

हालांकि, मुझे स्विफ्ट के साथ दूसरी भाषा से इंटरऑपरेट करने का कारण था और मुझे वैकल्पिक प्रकार में पास करना पड़ा।दुर्भाग्यवश, स्विफ्ट मुझे कारणों के कारण रनटाइम पर वैकल्पिक बनाने का तरीका प्रदान नहीं करता है (कम से कम मुझे कोई रास्ता नहीं मिला है), और मैं आसानी से नकल नहीं कर सकता क्योंकि वैकल्पिक जेनम के मामले में विकल्प लागू किए जाते हैं और enums एक enum के पेलोड पैक करने के लिए एक खराब दस्तावेज 5 रणनीति कार्यान्वयन का उपयोग करें। (value: T, present: Bool) जो अनुबंध है कि अगर presenttrue है, तो value अन्यथा वैध, अवैध होने की गारंटी है है:

मैं एक टपल कि मैं grins के लिए सिर्फ एक मेडुसा टपल कॉल करने के लिए जा रहा हूँ पारित करके इस के आसपास काम किया। मैं इस इंटरॉप को सुरक्षित रूप से अब उपयोग कर सकते हैं:

public func toOptional<T>(optTuple: (value:T, present:Bool)) -> T? 
{ 
    if optTuple.present { return optTuple.value } 
    else { return nil } 
} 

public func fromOptional<T>(opt: T?) -> (T, Bool) 
{ 
    if opt != nil { return (opt!, true) } 
    else { 
     return (defaultValue(), false) 
    } 
} 

इस तरह, मेरी बुला कोड एक वैकल्पिक और प्राप्त कोड के बजाय एक टपल में गुजरता है और यह एक वैकल्पिक (और रिवर्स) में बदल जाते हैं।

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