2014-12-08 112 views
6

我可以创建一个适用于(例如)字符串的数组扩展吗?是否可以在Swift中创建一个数组扩展?

+1

不确定你的意思 - 你能说更多关于你的意图吗?也许是一个例子? – dpassage 2014-12-08 03:28:15

+0

@dpassage你可以扩展事物的扩展类遵守协议(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html),我很好奇如果你可以进一步限制它只有一个类,以便我在Swift中的扩展只适用于字符串数组。 – 2014-12-08 03:32:29

+0

但是描述一下你想要这样的扩展到_do_。这只是一个功能问题吗?然后定义一个全局通用函数。给你一个你希望完成的实际用例。 – matt 2014-12-08 03:33:17

回答

12

作为夫特2的,但是现在可以用协议扩展, ,其对符合类型 (任选被附加约束限制)提供方法和属性的实现来实现。

一个简单的例子:定义符合所有类型的方法 到SequenceType(如Array),其中序列元件是String

extension SequenceType where Generator.Element == String { 
    func joined() -> String { 
     return "".join(self) 
    } 
} 

let a = ["foo", "bar"].joined() 
print(a) // foobar 

扩展方法不能用于struct Array定义直接,但只适用于符合某些协议(具有可选约束)的所有类型 。所以一个 必须找到协议Array符合,并提供所有必要的方法。在上例中,即SequenceType

又如(的How do I insert an element at the correct position into a sorted array in Swift?的变化):

extension CollectionType where Generator.Element : Comparable, Index : RandomAccessIndexType { 
    typealias T = Generator.Element 
    func insertionIndexOf(elem: T) -> Index { 
     var lo = self.startIndex 
     var hi = self.endIndex 
     while lo != hi { 
      // mid = lo + (hi - 1 - lo)/2 
      let mid = lo.advancedBy(lo.distanceTo(hi.predecessor())/2) 
      if self[mid] < elem { 
       lo = mid + 1 
      } else if elem < self[mid] { 
       hi = mid 
      } else { 
       return mid // found at position `mid` 
      } 
     } 
     return lo // not found, would be inserted at position `lo` 
    } 
} 

let ar = [1, 3, 5, 7] 
let pos = ar.insertionIndexOf(6) 
print(pos) // 3 

这里所述方法被定义为扩展到CollectionType因为需要 的元素下标访问,并且这些元件被要求 为Comparable

+0

您可以将'Index == Int'切换为'Index:RandomAccessIndexType',并稍作修改。 'startIndex'而不是'0','endIndex.predecessor()','let mid = lo.advancedBy(lo.distanceTo(hi)/ 2)'加上'isEmpty'上的提前保释。这意味着例如它可以与'String.UTF16View'一起使用,它是随机访问但不是整数索引。 – 2015-06-12 04:57:26

+0

@AirspeedVelocity:完成:) – 2015-06-12 06:16:43

5

更新:请参阅下面的关于Swift 2.0更新的Martin的回答。 (因为它被接受,我不能删除这个答案;如果道格可以接受马丁的回答,我会删除这一项,以避免将来出现混乱。)


这已经拿出了多次在论坛,答案是否定的,你今天不能这样做,但他们认为这是一个问题,他们希望在将来改进这一点。有些东西他们想要添加到stdlib,也需要这个。这就是为什么有这么多的免费功能是stdlib。他们大多数都是针对这个问题或“无默认实现”问题(即“特征”或“mixins”)的变通方法。

+2

谢谢,它确实看起来像一个奇怪的遗漏。将保持我的手指交叉。 – 2014-12-08 03:42:36

+0

可能要编辑这个2.0,特别是。因为愚蠢指的是它。 – 2015-06-12 04:58:48

0

尽管在评论中有很多请求,但您仍然没有给出用例,因此很难知道您要做什么。但是,正如我已经在评论中所说的(而罗布在回答中说过),你不会从字面上理解它;扩展不能以这种方式工作(目前)。

正如我在评论中所说,我会做的是将数组包装在结构中。现在结构保护并保证字符串的类型,并且我们有封装。下面是一个例子,但当然,你必须保持你已经没有给出这种事情你真的喜欢做的指示头脑,所以这可能不是直接满足:

struct StringArrayWrapper : Printable { 
    private var arr : [String] 
    var description : String { return self.arr.description } 
    init(_ arr:[String]) { 
     self.arr = arr 
    } 
    mutating func upcase() { 
     self.arr = self.arr.map {$0.uppercaseString} 
    } 
} 

而且这里是如何叫它:

let pepboys = ["Manny", "Moe", "Jack"] 
    var saw = StringArrayWrapper(pepboys) 
    saw.upcase() 
    println(saw) 

因此,我们已经有效地隔离我们的字符串数组到一个世界里,我们可以仅适用于字符串数组的功能布防。如果pepboys不是字符串数组,我们不能将它包装在StringArrayWrapper中以开始。

+0

如果数组可能很大,那么一个类可能比一个结构更好,这样就保证了通过引用传递。为了这个原因,我常常在类中包装大数组 - 所以传递它们不涉及复制。 – matt 2014-12-08 15:25:42

+0

Swift使用copy-on-write进行按值传递,因此在大多数情况下,传递大型数组不应该花费大量成本。如果你发现一个重要的成本,你应该打开一个雷达。苹果特别指出,出于性能原因,你不应该试图躲避复制。请参阅https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html底部的说明。 – 2014-12-08 18:33:12

+0

@RobNapier这里的属性是一个'var',并且该示例假定它会被写入。 – matt 2014-12-08 18:42:58

1

这已经被上面三位智者的回答;-),但我虚心地提供了@马丁的答案的概括。我们可以通过使用仅在我们希望定位的类上实现的“标记”协议来定位任意类。 IE浏览器。一个不必找到一个协议本身,但可以创建一个微不足道的用于定位所需的类。

protocol TargetType {} 
extension Array:TargetType {} 

struct Foo { 
    var name:String 
} 

extension CollectionType where Self:TargetType, Generator.Element == Foo { 
    func byName() -> [Foo] { return sort { l, r in l.name < r.name } } 
} 

let foos:[Foo] = ["c", "b", "a"].map { s in Foo(name: s) } 
print(foos.byName()) 
相关问题