19238


CollectionTypeプロトコルのリファレンスを見てみると、

次のように、宣言されています。  
subscript( _: Self.Index) -> Self.Base.Generator.Element  
subscript(_: Self.Index) -> Self.Generator.Element

Selfは、CollectionTypeプロトコルが具体的に使用される型となる理解しています。

ただ次の型の意味が理解できません。  
Self.Base.Generator.Element  
Self.Generator.Element

の違い・意味分かりません。特に「Base」がわかりません。


CC BY-SA 3.0
2015-11-24T03:09:34.440
19228
2015-11-24T08:41:24.183
2015-11-24T05:28:18.017
11148
11148
question
swift
型宣言と付属型の仕組み


[`subscript(_: Self.Index) ->
Self.Base.Generator.Element`](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_CollectionType_Protocol/index.html#//apple_ref/swift/intfsub/CollectionType/s:seRq_Ss14CollectionTypeq_Ss22_CollectionWrapperTypezqq_Ss9Indexable5Indexqqq_S0_4BaseS1_5Indexzqqq_S1_5IndexSs16ForwardIndexType8Distanceqqqq_S0_4BaseS1_5IndexS2_8Distancezqqq_S1_5IndexS2_19_DisabledRangeIndexqqqq_S0_4BaseS1_5IndexS2_19_DisabledRangeIndexzqqqq_S1_5IndexS2_8DistanceSs25IntegerLiteralConvertible18IntegerLiteralTypeqqqqq_S0_4BaseS1_5IndexS2_8DistanceS3_18IntegerLiteralType_SsS_9subscriptFqq_S1_5Indexqqqq_S0_4BaseSs12SequenceType9GeneratorSs13GeneratorType7Element)
の定義に _Default Implementation_ という注釈がある通り、こちらはデフォルト実装の定義であり、  
`CollectionType` プロトコルとしての要求はあくまで[`subscript(_: Self.Index) ->
Self.Generator.Element`](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_CollectionType_Protocol/index.html#//apple_ref/swift/intfsub/CollectionType/s:sPSs14CollectionType9subscriptFqq_Ss9Indexable5Indexqqq_S_9GeneratorSs13GeneratorType7Element)
です。

`subscript(_: Self.Index) -> Self.Base.Generator.Element` のほうを開くと、

> Constraints
[code]

>     Self : _CollectionWrapperType, Self.Index == Self.Base.Index
>  
[/code]

というのが見えると思いますが、これは「(`CollectionType`である)`Self` が `_CollectionWrapperType`
であり、かつ`Self.Index` が `Self.Base.Index` と同じ型であるとき」に、デフォルトの実装が提供されますという意味になります。  
つまり、ここでの `Base` は `_CollectionWrapperType` の `Base` であり、 `CollectionType`
とは直接の関係はありません。

理解するには `_CollectionWrapperType` を知っておく必要があると思うので、説明します。  
`_CollectionWrapperType` はドキュメントには載っていないですが私たちも使用することが可能なプロトコルで、定義は下記の通りです。

[code]

    public protocol _CollectionWrapperType : _SequenceWrapperType {
        typealias Base : CollectionType
        typealias Index : ForwardIndexType = Self.Base.Index
        var _base: Self.Base { get }
    }
    
    public protocol _SequenceWrapperType {
        typealias Base : SequenceType
        typealias Generator : GeneratorType = Self.Base.Generator
        var _base: Self.Base { get }
    }
    
[/code]

これを満たすような最小の実装としては:

[code]

    struct FooBarBaz: _CollectionWrapperType {
        let _base = ["foo", "bar", "baz"]
    }
    
[/code]

こんな感じです。ここで `Base` は `_base` の型から推測されて`Array<String>`、`Index` は デフォルトで
`Array<String>.Index` である `Int`、`Generator` は同様に
`IndexingGenerator<Array<String>>` になります。何も省略しないで書くなら:

[code]

    struct FooBarBaz: _CollectionWrapperType {
        typealias Base = Array<String>
        typealias Index = Int
        typealias Generator = IndexingGenerator<Array<String>>
        let _base = ["foo", "bar", "baz"]
    }
    
[/code]

このままだと、何のメソッドも持っていない、`_base`プロパティだけを持つただの構造体ですが、これを `CollectionType`
に準拠するように宣言します。

[code]

    struct FooBarBaz: _CollectionWrapperType, CollectionType {
        //                                  ^^^^^^^^^^^^^^^^ これを加えただけ
        let _base = ["foo", "bar", "baz"]
    }
    
[/code]

この瞬間、先ほどの「(`CollectionType`である)`Self` が `_CollectionWrapperType`
であり、かつ`Self.Index` が `Self.Base.Index`
と同じ型であるとき」の条件を満たしたことになり、自動的に`subscript(_: Self.Index) ->
Self.Base.Generator.Element`
を含むいくつかのメソッドのデフォルト実装が提供され、かつそれで`CollectionType`である要件をすべて満たすようになるので、`FooBarBaz`
はそのまま`CollectionType`として使用できます。

[code]

    struct FooBarBaz: _CollectionWrapperType, CollectionType {
        let _base = ["foo", "bar", "baz"]
    }
    
    let fbb = FooBarBaz()
    print(fbb[0]) // -> "foo"
    print(fbb.count) // -> 3
    print(fbb.joinWithSeparator("|")) // -> "foo|bar|baz"
    
[/code]

というわけで `_CollectionWrapperType`
はコレクションをラッピングしつつコレクションのように振る舞う型を作りたいときの便利ツールです。もっとも今のところundocumentedなので、自己責任で使用する必要がありますが・・・

ちなみに、この例では、`Self.Generator == Self.Base.Generator` なので当然
`Self.Genenerator.Element == Self.Base.Generator.Element` となりデフォルト実装が提供された
`subscript` がそのまま `CollectionType` のメソッドとして使用できますが、 `Self.Genenerator.Element
!= Self.Base.Generator.Element`
のときはデフォルト実装は提供されますが、`CollectionType`の要件は満たさなくなってしまいますので、その場合は、自前で
`subscript(_: Self.Index) -> Self.Generator.Element` などのメソッドを実装する必要があります。


CC BY-SA 3.0
2015-11-24T08:31:03.177
19238
2015-11-24T08:41:24.183
2015-11-24T08:41:24.183
3489
3489
19228
answer