2 回答

TA貢獻1829條經驗 獲得超7個贊
和其他對象一樣當做參數使用即可。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | fun function(x: [Int]) { // 打印所有元素 print(x)
// 生成一個新數組,每個元素都是原數組的二倍 let y = x.map { $0 * 2 } // 新數組結果應該是 [2, 4, 6, 8, 10] print(y)
// 所有數組元素求和,0 表示初始化一個值為零的和變量 let z = x.reduce(0) { $0 + $1 } // z 的結果應該是 1 + 2 + 3 + 4 + 5 = 15 print(z) }
let a = [1, 2, 3, 4, 5] function(x: a) |

TA貢獻1799條經驗 獲得超6個贊
Swift的數組是一個結構體類型,它遵守了CollectionType、MutableCollectionType、_DstructorSafeContainer協議,其中最重要的就是CollectionType協議,數組的一些主要功能都是通過這個協議實現的。而CollectionType協議又遵守Indexable和SequenceType這兩個協議。而在這兩個協議中,SequenceType協議是數組、字典等集合類型最重要的協議,在文檔中解釋了SequenceType是一個可以通過for...in循環迭代的類型,實現了這個協議,就可以for...in循環了。
A type that can be iterated with a for...in loop.
而SequenceType是建立在GeneratorType基礎上的,sequence需要GeneratorType來告訴它如何生成元素。
GeneratorType
GeneratorType協議有兩部分組成:
它需要有一個Element關聯類型,這也是它產生的值的類型。
它需要有一個next方法。這個方法返回Element的可選對象。通過這個方法就可以一直獲取下一個元素,直到返回nil,就意味著已經獲取到了所有元素。
/// Encapsulates iteration state and interface for iteration over a
/// sequence.
///
/// - Note: While it is safe to copy a generator, advancing one
/// copy may invalidate the others.
///
/// Any code that uses multiple generators (or `for`...`in` loops)
/// over a single sequence should have static knowledge that the
/// specific sequence is multi-pass, either because its concrete
/// type is known or because it is constrained to `CollectionType`.
/// Also, the generators must be obtained by distinct calls to the
/// sequence's `generate()` method, rather than by copying.
public protocol GeneratorType {
/// The type of element generated by `self`.
associatedtype Element
/// Advance to the next element and return it, or `nil` if no next
/// element exists.
///
/// - Requires: `next()` has not been applied to a copy of `self`
/// since the copy was made, and no preceding call to `self.next()`
/// has returned `nil`. Specific implementations of this protocol
/// are encouraged to respond to violations of this requirement by
/// calling `preconditionFailure("...")`.
@warn_unused_result
public mutating func next() -> Self.Element?
}
我把自己實現的數組命名為MYArray,generator為MYArrayGenerator,為了簡單,這里通過字典來存儲數據,并約定字典的key為從0開始的連續數字。就可以這樣來實現GeneratorType:
/// 需保準dic的key是從0開始的連續數字
struct MYArrayGenerator<T>: GeneratorType {
private let dic: [Int: T]
private var index = 0
init(dic: [Int: T]) {
self.dic = dic
}
mutating func next() -> T? {
let element = dic[index]
index += 1
return element
}
}
這里通過next方法的返回值,隱式地為Element賦值。顯式地賦值可以這樣寫typealias Element = T。要使用這個生成器就非常簡單了:
let dic = [0: "XiaoHong", 1: "XiaoMing"]
var generator = MYArrayGenerator(dic: dic)
while let elment = generator.next() {
print(elment)
}
// 打印的結果:
// XiaoHong
// XiaoMing
SequenceType
有了generator,接下來就可以實現SequenceType協議了。SequenceType協議也是主要有兩部分:
需要有一個Generator關聯類型,它要遵守GeneratorType。
要實現一個generate方法,返回一個Generator。同樣的,我們可以通過制定generate方法的方法類型來隱式地設置Generator:
struct MYArray<T>: SequenceType {
private let dic: [Int: T]
func generate() -> MYArrayGenerator<T> {
return MYArrayGenerator(dic: dic)
}
}
這樣我們就可以創建一個MYArray實例,并通過for循環來迭代:
let dic = [0: "XiaoHong", 1: "XiaoMing", 2: "XiaoWang", 3: "XiaoHuang", 4: "XiaoLi"]
let array = MYArray(dic: dic)
for value in array {
print(value)
}
let names = array.map { $0 }
當然,目前這個實現還存在很大的隱患,因為傳入的字典的key是不可知的,雖然我們限定了必須是Int類型,但無法保證它一定是從0開始,并且是連續,因此我們可以通過修改初始化方法來改進:
init(elements: T...) {
dic = [Int: T]()
elements.forEach { dic[dic.count] = $0 }
}
然后我們就可以通過傳入多參數來創建實例了:
let array = MYArray(elements: "XiaoHong", "XiaoMing", "XiaoWang", "XiaoHuang", "XiaoLi")
再進一步,通過實現ArrayLiteralConvertible協議,我們可以像系統的Array數組一樣,通過字面量來創建實例:
let array = ["XiaoHong", "XiaoMing", "XiaoWang", "XiaoHuang", "XiaoLi"]
最后還有一個數組的重要特性,就是通過下標來取值,這個特性我們可以通過實現subscript方法來實現:
extension MYArray {
subscript(idx: Int) -> Element {
precondition(idx < dic.count, "Index out of bounds")
return dic[idx]!
}
}
print(array[3]) // XiaoHuang
至此,一個自定義的數組就基本實現了,我們可以通過字面量來創建一個數組,可以通過下標來取值,可以通過for循環來遍歷數組,可以使用map、forEach等高階函數。
小結
要實現一個數組的功能,主要是通過實現SequenceType協議。SequenceType協議有一個Generator實現GeneratorType協議,并通過Generator的next方法來取值,這樣就可以通過連續取值,來實現for循環遍歷了。同時通過實現ArrayLiteralConvertible協議和subscript,就可以通過字面量來創建數組,并通過下標來取值。
CollectionType
上面我們為了弄清楚SequenceType的實現原理,通過實現SequenceType和GeneratorType來實現數組,但實際上Swift系統的Array類型是通過實現CollectionType來獲得這些特性的,而CollectionType協議又遵守Indexable和SequenceType這兩個協議。并擴展了兩個關聯類型Generator和SubSequence,以及9個方法,但這兩個關聯類型都是默認值,而且9個方法也都在協議擴展中有默認實現。因此,我們只需要為Indexable協議中要求的 startIndex 和 endIndex 提供實現,并且實現一個通過下標索引來獲取對應索引的元素的方法。只要我們實現了這三個需求,我們就能讓一個類型遵守 CollectionType 了。因此這個自定義的數組可以這樣實現:
struct MYArray<Element>: CollectionType {
private var dic: [Int: Element]
init(elements: Element...) {
dic = [Int: Element]()
elements.forEach { dic[dic.count] = $0 }
}
var startIndex: Int { return 0 }
var endIndex: Int { return dic.count }
subscript(idx: Int) -> Element {
precondition(idx < endIndex, "Index out of bounds")
return dic[idx]!
}
}
extension MYArray: ArrayLiteralConvertible {
init(arrayLiteral elements: Element...) {
dic = [Int: Element]()
elements.forEach { dic[dic.count] = $0 }
}
}
- 2 回答
- 0 關注
- 713 瀏覽
添加回答
舉報