Swift中没有默认值(T)吗?

时间:2014-06-10 08:46:48

标签: swift generics

我正在尝试将Swift本书中的Matrix示例移植为通用。

这是我到目前为止所得到的:

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传递给构造函数。

在C#中,我会使用default(T)0表示数字,false表示布尔值,null表示引用类型。我理解Swift不允许nil使用非可选类型,但我仍然很好奇,如果传递一个显式参数是唯一的方法,或者如果我有某些相当于{ {1}}那里。

3 个答案:

答案 0 :(得分:6)

没有。 Swift强制您指定默认值,就像处理变量和字段一样。 Swift具有默认值概念的唯一情况是可选类型,其中nilOptional.None)。

答案 1 :(得分:5)

一个iffy'是'。您可以使用协议约束来指定您的泛型类或函数仅适用于实现默认初始化函数(无参数)的类型的要求。这种情况的后果很可能是坏的(它不会像你想象的那样起作用),但它与你要求的最接近,可能比“否”答案更接近。

对我来说,我发现这个在开发新的泛型类时会有所帮助,然后我最终删除了约束并修复了剩下的问题。仅要求可以采用默认值的类型将限制通用数据类型的有用性。

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 :(得分:3)

有一种方法可以在swift中获得等效的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

在问题行中,Swift认为t已经初始化,因为Swift的语义是这样的:你不能拥有一个未初始化的值类型的变量。除了因为default<T>打破了那些语义。当您执行赋值时,Swift会向值见证表发出一个调用以销毁现有类型。这将包括将在字段release上调用x的代码,因为Swift语义表示对象的实例永远不会nil。然后你就会遇到运行时崩溃。

但是,我有理由从另一种语言与Swift互操作,我不得不传入一个可选类型。不幸的是,Swift没有为我提供一种在运行时构造可选的方法,原因是(至少我没有找到方法),而且我不能轻易地模拟一个,因为选项被实现了在通用枚举和枚举方面,使用记录不完整的5策略实现来打包枚举的有效负载。

我通过传递一个元组来解决这个问题,我将打电话给美杜莎元组只是为了咧嘴笑:(value: T, present: Bool)它的合同是presenttrue,然后保证value有效,否则无效。我现在可以安全地使用它来互操作:

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

通过这种方式,我的调用代码传递一个元组而不是一个可选的接收代码并将其转换为可选代码(反之)。