Swift通用构造函数

Peh*_*eje 3 generics swift

这些问题嵌入在评论和以下内容中:

  1. 如何在参数列表中定义通用T的默认值?
  2. 在Swift中复制参数时,它是指针还是对象?
    • XCode Beta 7告诉我,我无法改变"head",因为它是"let",请参阅代码
  3. 任何类似Swift的方式来循环检查nil以避免展开?

链接列表实现:

public class Node<T>
{
    public var data: T
    public var next: Node<T>?

    //1.
    //How can I define a default datatype for T?
    //In C++ I would let T ctor do it: "data: T = T()" gives 
    //error: 'T' cannot be constructed because it has no accessible initializers
    public init(data: T, next: Node<T>?)
    {
        self.data = data
        self.next = next
    }
}

func print<T>(head: Node<T>)
{
    var tmp = head  //2. Is this a copy of a pointer or an object?
    print(tmp.data)
    while(tmp.next != nil)  //3. Any Swiftier way to do it?
    {
        tmp = tmp.next!
        print(tmp.data)
    }
}

func insert<T>(head: Node<T>, _ value: T)
{
    var tmp = head
    while tmp.next != nil
    {
        tmp = tmp.next!
    }
    tmp.next = Node<T>(data: value, next: nil)
}

var head = Node<Int>(data: 1, next: nil)
insert(head, 2)
insert(head, 4)
insert(head, 8)
insert(head, 16)
print(head)
Run Code Online (Sandbox Code Playgroud)

还有,还有其他意见吗?我对Swift很新

Kam*_*xom 10

1.

泛型是关于代码安全的,而不知道编译时的类型.这意味着将泛型类型初始化为某些东西是没有意义的.但是通过声明一个类似的协议

protocol Initializable {
    init()
}
Run Code Online (Sandbox Code Playgroud)

,通过执行扩展您想要使用的类型

extension Int : Initializable {}
Run Code Online (Sandbox Code Playgroud)

(也许init()自己实现这个方法)并声明你的节点

public class Node<T: Initializable>
Run Code Online (Sandbox Code Playgroud)

您可以T()在初始化程序中使用它来创建初始值.因为现在编译器知道这种类型确实具有这样的初始化器,因为它符合该协议.

2.

总是作为引用传递,而结构总是被复制

为了能够更改函数的输入值,必须将其声明为inoutlike

func insert<T>(inout head: Node<T>, _ value: T)
Run Code Online (Sandbox Code Playgroud)

然后你还需要调用这个函数 insert(&head, 2)

3.

你可以像写一样循环

while let next = tmp.next {
    tmp = next
    print(tmp.data)
}
Run Code Online (Sandbox Code Playgroud)

4.

Swift是一种美妙的语言,我强烈建议你一般使用更多的Swiftier代码.

你编写这两个方法的方式就像在C中一样.你可以把函数放在类中,这是最好的方法,它也更简单.

我承认不是很重要,但这种大括号的风格已经过时了

如果您不需要,则无需将函数声明为公共函数.在编写框架或类似的东西时,你只需要它.默认行为(无访问控制修饰符)是访问整个项目中的所有Swift文件.

Initializable我在这里制定的这个协议也不是真正的Swifty

周围while (boolean)的支架不需要,也不是Swifty

命名参数有一个原因:使代码更具可读性.只有当你完全确定它很烦人并且清楚参数代表什么时才删除它们.

我最初不想这样做,但我以更加Swifty的方式重新编写代码,我希望我可以帮助你:

protocol DefaultValuable {
    static func defaultValue() -> Self
}

extension Int : DefaultValuable {
    static func defaultValue() -> Int {
        return 1
    }
}

class Node<T: DefaultValuable> {
    var data: T
    var next: Node<T>?

    init(data: T = T.defaultValue(), next: Node<T>? = nil) {
        self.data = data
        self.next = next
    }

    func printNode() {
        var tmp = self
        print(tmp.data)

        while let next = tmp.next {
            tmp = next
            print(tmp.data)
        }
    }

    func insert(value: T) {
        var tmp = self

        while let next = tmp.next {
            tmp = next
        }

        tmp.next = Node<T>(data: value)
    }
}

let head = Node<Int>()
head.insert(2)
head.insert(4)
head.insert(8)
head.insert(16)
head.printNode()
Run Code Online (Sandbox Code Playgroud)

(抱歉有点咆哮)