32171

[code]

    func methodA<T:ExpressibleByIntegerLiteral>(n:T)->(){
    
        var i = 1
        var j = T(integerLiteral:i) 
    }
    
[/code]

上記の関数は、「var j = T(integerLiteral:i) 」でコンパイルエラーとなります。

しかし、私の解釈では、T型は、ExpressibleByIntegerLiteralプロトコルに準拠しているとしており、またプロトコルは、init(integerLiteral:)[REQUIRED]とあるので、なぜエラーとなるのかが理解ができません。  
私は何が理解できていないのでしょうか。教えてください。


CC BY-SA 3.0
2017-01-26T09:07:41.340
32170
2017-01-26T10:34:44.173
11148
question
swift swift3
プロトコルの準拠について


私も一瞬、「なんでこれがダメなんだろう?」と思ってしまった側なんですが…。

まずはプロトコル`ExpressibleByIntegerLiteral`の定義を再確認してみましょう。

>
[code]

>     /// Conforming types can be initialized with integer literals.
>     public protocol ExpressibleByIntegerLiteral {
>  
>         associatedtype IntegerLiteralType
>  
>         /// Create an instance initialized to `value`.
>         public init(integerLiteral value: Self.IntegerLiteralType)
>     }
>  
[/code]

`init(integerLiteral:)`メソッド(イニシャライザ)のパラメータ型は`Int`ではなく、`Self.IntegerLiteralType`になっています。あなたが`T:
ExpressibleByIntegerLiteral`以外の何の制約も与えず`func
methodA<T:ExpressibleByIntegerLiteral>(n:T)->()`でメソッド宣言をした場合、`T.IntegerLiteralType`は`Int`しかないと決定付けることはできず、メソッド本体は(今は定義されていなくとも、可能性としてありえる)任意の`T.IntegerLiteralType`について動作するように記述しないといけません。

よって、`var i =
1`で`Int`型と決定されてしまった`i`を引数にして`init(integerLiteral:)`を呼ぶことはできない、と言うことになってエラーが発生しているわけです。

したがって、これは構文エラーにはなりません。

[code]

    func methodA<T: ExpressibleByIntegerLiteral>(n: T) -> ()
        where T.IntegerLiteralType == Int
    {
        var i = 1
        var j = T(integerLiteral: i)
        //...
    }
    
[/code]

あるいは、こんな書き方をすることもできます。

[code]

    func methodA<T: ExpressibleByIntegerLiteral>(n: T) -> () {
        var j: T = 1
        //...
    }
    
[/code]

何となく雰囲気くらいはつかんでいただけたでしょうか。ジェネリックを使った宣言は、「制約を満たすどんなデータ型が来ても動くように書かないとエラーになってしまう」と言うことを頭に叩き込んだ上で、プロトコルの定義などを見直せば、より理解が深まるかと思います。


CC BY-SA 3.0
2017-01-26T10:34:44.173
32171
2017-01-26T10:34:44.173
13972
32170
answer