我如何在Swift中扩展类型化数组?

16 浏览
0 Comments

我如何在Swift中扩展类型化数组?

如何使用自定义的函数工具扩展Swift的ArrayT[]类型?\n浏览Swift的API文档显示,Array的方法是T[]的扩展,例如:\nextension T[] : ArrayType {\n //...\n init()\n var count: Int { get }\n var capacity: Int { get }\n var isEmpty: Bool { get }\n func copy() -> T[]\n}\n\n当复制和粘贴相同的源代码并尝试任何变化时,例如:\nextension T[] : ArrayType {\n func foo(){}\n}\nextension T[] {\n func foo(){}\n}\n\n它无法构建,出现错误:\n

\n无法扩展名为T[]的名义类型\n

\n使用完整的类型定义会出现Use of undefined type \'T\'的错误,即:\nextension Array {\n func foo(){}\n}\n\n它也无法使用ArrayArray。\n有趣的是,Swift允许我扩展一个未定义类型的数组,例如:\nextension Array {\n func each(fn: (Any) -> ()) {\n for i in self {\n fn(i)\n }\n }\n}\n\n然后可以这样调用:\n

[1,2,3].each(println)

\n但是我无法创建一个正确的泛型类型扩展,因为当它通过方法时,类型似乎丢失了,例如尝试用自定义的filter替换Swift的内置filter:\nextension Array {\n func find(fn: (T) -> Bool) -> T[] {\n var to = T[]()\n for x in self {\n let t = x as T\n if fn(t) {\n to += t\n }\n }\n return to\n }\n}\n\n但是编译器将其视为无类型,仍然允许使用以下方式调用扩展:\n[\"A\",\"B\",\"C\"].find { $0 > \"A\" }\n\n当使用调试器单步调试时,指示类型为Swift.String,但在未将其转换为String的情况下,尝试访问它时会出现构建错误,即:\n[\"A\",\"B\",\"C\"].find { ($0 as String).compare(\"A\") > 0 }\n\n有人知道创建一个行为类似于内置扩展的类型扩展方法的正确方法吗?

0
0 Comments

问题原因:使用Swift时,有时候我们希望扩展已有的类型。在这个问题中,我们想要扩展Swift中的typed Arrays,即具有特定类型的数组。

解决方法:我们可以使用Swift的extension关键字来实现这个目标。下面是一些扩展typed Arrays的示例:

1. 扩展所有类型:

extension Array where Element: Any {

// ...

}

2. 扩展Comparable类型:

extension Array where Element: Comparable {

// ...

}

3. 扩展某些类型(同时满足Comparable和Hashable):

extension Array where Element: Comparable & Hashable {

// ...

}

4. 扩展特定类型(例如Int):

extension Array where Element == Int {

// ...

}

通过使用这些extension,我们可以为typed Arrays添加自定义的功能和行为,从而更好地满足我们的需求。

0
0 Comments

问题的出现是因为原来的代码在使用泛型类型时出现了编译错误。解决方法是从函数的签名中移除,并将x直接作为T类型使用,同时使用append方法将符合条件的元素添加到返回的数组中。

以下是整理后的文章:

在尝试了不同的方法之后,解决方案似乎是从签名中移除,像这样:

extension Array {

func find(fn: (T) -> Bool) -> [T] {

var to = [T]()

for x in self {

if fn(x) {

to.append(x)

}

}

return to

}

}

现在,这段代码按预期工作并且没有编译错误:

["A","B","C"].find { $0.compare("A") > 0 }

顺便说一句,你在这里定义的函数与现有的filter函数在功能上是等效的:

let x = ["A","B","C","X”].filter { $0.compare("A") > 0 }

不,不是的,内置的filter函数会执行两次回调

我明白了。对我来说,双重过滤似乎相当有问题...但这仍然符合filter与你的find的功能等效,也就是说函数的结果是相同的。如果你的过滤闭包具有副作用,你可能不会喜欢结果,当然。

确切地说,内置的filter具有意外的行为,而上面的find实现按预期工作(也是为什么它存在的原因)。如果闭包执行两次,这就不是功能上等效的,因为它可能潜在地改变作用域变量(这是我遇到的一个错误,因此才会提出这个问题)。还请注意,问题明确提到想要替换Swift的内置filter。

我们似乎在争论“函数式”一词的定义。在函数式编程范式中,filter、map和reduce函数的产生是为了执行它们的返回值。相比之下,你上面定义的each函数是一个执行副作用的函数,因为它没有返回值。我想我们可以同意当前的Swift实现并不理想,文档也没有说明它的运行时特性。

对我来说,似乎不需要将x强制转换为T类型,所以,假设这是正确的,你可以省略let语句,并直接引用x。let语句末尾的分号也是不必要的。由于从beta 5开始,+=只用于连接数组,现在你必须使用append方法将符合条件的元素添加到返回的数组中。

0
0 Comments

在Swift中如何扩展类型数组?

在Swift中,我们可以使用extension关键字来扩展类、结构体和类型别名。但是,当我们想要扩展一个已经指定了类型的数组时,可能会遇到一些问题。

比如,如果我们想要给一个指定了类型的数组排序,可以使用下面的代码来实现:

class HighScoreEntry {

let score:Int

}

extension Array where Element == HighScoreEntry {

func sort() -> [HighScoreEntry] {

return sort { $0.score < $1.score }

}

}

这段代码使用了extension关键字来扩展了一个指定类型为HighScoreEntry的数组,实现了对数组进行排序的功能。

但是,如果我们尝试使用结构体或类型别名来实现同样的功能,就会遇到错误:

Type 'Element' constrained to a non-protocol type 'HighScoreEntry'

这是因为Swift要求我们使用协议类型来约束泛型类型,而结构体和类型别名并不满足这个要求。

为了解决这个问题,我们可以使用另一种方法来扩展非类的数组类型。例如,可以使用下面的代码来排序一个指定类型为Int的数组:

typealias HighScoreEntry = (Int)

extension Sequence where Iterator.Element == HighScoreEntry {

func sort() -> [HighScoreEntry] {

return sort { $0 < $1 }

}

}

这段代码使用了typealias关键字定义了一个类型别名HighScoreEntry,并使用extension关键字扩展了一个指定类型为HighScoreEntry的数组,实现了对数组进行排序的功能。

在Swift 3中,一些类型的名称发生了改变。例如,SequenceType被重命名为Sequence。因此,在Swift 3中,我们需要使用下面的代码来扩展指定类型为HighScoreEntry的数组:

extension Sequence where Iterator.Element == HighScoreEntry {

// ...

}

另外,从Swift 3.1开始,我们可以使用下面的语法来扩展指定类型为Int的数组:

extension Array where Element == Int {

// ...

}

总结起来,要在Swift中扩展指定类型的数组,我们可以使用extension关键字,并根据具体的情况选择适合的约束条件。

0