Is there no default(T) in Swift?

前端 未结 3 2244
感情败类
感情败类 2021-02-18 22:40

I\'m trying to port the Matrix example from Swift book to be generic.

Here\'s what I got so far:

struct Matrix {
    let rows: Int, columns: Int         


        
相关标签:
3条回答
  • 2021-02-18 23:14

    An iffy 'YES'. You can use protocol constraints to specify the requirement that your generic class or function will only work with types that implement the default init function (parameter-less). The ramifications of this will most likely be bad (it doesn't work the way you think it does), but it is the closest thing to what you were asking for, probably closer than the 'NO' answer.

    For me I found this personally to be helpful during development of a new generic class, and then eventually I remove the constraint and fix the remaining issues. Requiring only types that can take on a default value will limit the usefulness of your generic data type.

    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() )
      }
    }
    
    0 讨论(0)
  • 2021-02-18 23:19

    There isn't. Swift forces you to specify the default value, just like then you handle variables and fields. The only case where Swift has a concept of default value is for optional types, where it's nil (Optional.None).

    0 讨论(0)
  • 2021-02-18 23:32

    There is a way to get the equivalent of default(T) in swift, but it's not free and it has an associated hazard:

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

    Now this is clearly a hack because we don't know if alloc() initializes to something knowable. Is it all 0's? Stuff left over in the heap? Who knows? Furthermore, what it is today could be something different tomorrow.

    In fact, using the return value for anything other than a placeholder is dangerous. Let's say that you have code like this:

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

    At the problem line, Swift thinks that t has been initialized because that's what Swift's semantics say: you cannot have a variable of a value type that is uninitialized. Except that it is because default<T> breaks those semantics. When you do the assignment, Swift emits a call into the value witness table to destroy the existing type. This will include code that will call release on the field x, because Swift semantics say that instances of objects are never nil. And then you get a runtime crash.

    However, I had cause to interoperate with Swift from another language and I had to pass in an optional type. Unfortunately, Swift doesn't provide me with a way to construct an optional at runtime because of reasons (at least I haven't found a way), and I can't easily mock one because optionals are implemented in terms of a generic enum and enums use a poorly documented 5 strategy implementation to pack the payload of an enum.

    I worked around this by passing a tuple that I'm going to call a Medusa tuple just for grins: (value: T, present: Bool) which has the contract that if present is true, then value is guaranteed to be valid, invalid otherwise. I can use this safely now to interop:

    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)
        }
    }
    

    In this way, my calling code passes in a tuple instead of an optional and the receiving code and turn it into an optional (and the reverse).

    0 讨论(0)
提交回复
热议问题