2016-05-27 5 views
1

私はプロトコルとその拡張とプロトコルに準拠したクラスを持っています。プロトコル拡張で `inout`を使用できますか?

protocol WarAbilities { 
    var strength: Int { get set } 
    func attack(inout opponent: WarAbilities) 
} 

extension WarAbilities { 
    func attack(inout opponent: WarAbilities) { 
     opponent.strength -= 1 
    } 
} 

class Warrior: WarAbilities { 
    var strength: Int 

    init(strength: Int) { 
     self.strength = strength 
    } 
} 

私は2人の戦士が戦うようにしたい場合:

let thug1 = Warrior(strength: 10) 
let thug2 = Warrior(strength: 30) 

thug1.attack(&thug2) 

私は、このエラーメッセージが出ます:

error: cannot pass immutable value of type 'WarAbilities' as inout argument

mutatingを追加するには有望に見えた:

protocol WarAbilities { 
    var strength: Int { get set } 
    mutating func attack(inout opponent: WarAbilities) 
} 

extension WarAbilities { 
    mutating func attack(inout opponent: WarAbilities) { 
     opponent.strength -= 1 
    } 
} 

しかし、コンパイラは満足していないどちらかと私は新しいエラーメッセージが何を意味するのか理解できない:Warrior以来

error: cannot pass immutable value as inout argument: implicit conversion from 'Warrior' to 'WarAbilities' requires a temporary

WarAbilitiesに準拠して、私はそれらの1が仕事だろうと思った - しかし、スウィフトは、この種のを持っていないように見えます。 ..共分散?私がここで何を話しているのか分からない。

私の間違いは?

答えて

3

classプロトコル作成し、(当時)不要inoutものを取り除く:あなたがすべてで、ここでのプロトコルを必要とする理由

protocol WarAbilities : class { 
    var strength: Int { get set } 
    func attack(opponent: WarAbilities) 
} 

extension WarAbilities { 
    func attack(opponent: WarAbilities) { 
     opponent.strength -= 1 
    } 
} 

class Warrior: WarAbilities { 
    var strength: Int 

    init(strength: Int) { 
     self.strength = strength 
    } 
} 

let thug1 = Warrior(strength: 10) 
let thug2 = Warrior(strength: 30) 

thug1.attack(thug2) 

thug2.strength // 29 

は(実際に、それは私にはかなり不明だ。戦士がクラスであるため、 、あなただけWarAbilitiesそのスーパークラスを作ることができる)

2

2つのことが私の意見で間違っている:。

  1. はを渡しますinoutinout

このパラメータを上書きしないので、あなたの例では、あなたもinoutを必要としないことを注意、しかしそのパラメータの一部インスタンスメンバーとしてサブタイプを渡す

  • に-constant。単にinoutを削除するだけで、必要がないため、おそらくあなたのケースで動作します。(この問題を適切に処理するためのmattの回答を参照)mutatingを使用すると、おそらくパラメータのメンバーではなくメンバーを変更することしか話していないので、mutatingを使用すると、ここではうまく行かない可能性があります。


    問題の説明:

    protocol A {} 
    class B : A {} 
    
    func c(inout d : A) {} 
    
    let a = B() 
    c(&a) 
    

    aが一定であるため、最初に動作しません:
    正確に同じ問題の出力を生成はるかに簡単な問題を検討することができます。したがって、letvarに変更してください。
    その後、コンパイラは一時的な要求について不平を言います。これは非常に混乱しやすいエラーメッセージですが、問題は実際には意味があります。

    あなたはプロトコル

    解説期待inoutinoutまたはいくつかのプロトコルの実装にいくつかの種類のサブタイプを渡すことはできません - 次の例を考えてみます。どうするか

    class A {} 
    class B : A {} 
    
    func c(inout a : A) { a = A() } 
    

    をあなたがそのメソッドを呼び出す場合は、

    var b = B() 
    c(&b) 
    

    bが変更され、今度はaと同じになりますが、aBであり、bと言われています。以下は再び動作することを

    注:

    var b : A = B() 
    c(&b) 
    

    我々はBに渡すが、実際には、それはAことを心配します。同じプロトコルのために行く:プロトコルをサポートして

    protocol P {} 
    class K : P {} 
    class X : P {} 
    
    func f(inout p : P) { p = X() } 
    
    var k = K() 
    f(&k) // does not work 
    
    var p : P = K() 
    f(&p) // works 
    
  • +0

    "あなたの例では、あなたはパラメータを上書きしないので、inoutは必要ないことに注意してください。 "You're wronそれについてg。彼は引数として渡されたインスタンスのプロパティを変更しようとしています。 'inout'がなければ、これは構造体パラメータの場合にはできません。だからこそ私の答えでは、これを 'class'プロトコルにしているので、コンパイラはこれがstructのパラメータではないことを知っています。 – matt

    +0

    @matt 'inout'は、構造体またはクラスであることを気にせず、定数であるかどうかを気にします。構造体を渡すことはまったく同じ方法で行います。クラスのみのプロトコルを使用すると、構造体の突然変異の根底にある問題が取り除かれます。しかし、それは 'inout'とは関係がありません。あなたは' inout'として渡された構造体を上書きすることは確かに許可されています。 – luk2302

    +0

    @mattあなたのコメントをもう一度読んだ後、あなたは 'inout'の必要性について部分的に正しいことに同意する必要があります。だから私の答えの最初のマイナーな部分は間違っています、はい。幸いにも、それは残りの議論と推論を変えない。 – luk2302

    0

    INOUT:

    protocol IPositional{ 
        func setPosition(position:CGPoint) 
    } 
    extension IPositional{ 
        var positional:IPositional {get{return self as IPositional}set{}} 
    } 
    class A:IPositional{ 
        var position:CGPoint = CGPoint() 
        func setPosition(position:CGPoint){ 
         self.position = position 
        } 
    } 
    func test(inout positional:IPositional){ 
        positional.setPosition(CGPointMake(10,10)) 
    } 
    var a = A() 
    test(&a.positional) 
    a.position//(10.0, 10.0) 
    

    結論:
    このようにそれをすることの利点:あなたは今、一つの「INOUTメソッドを持つことができるということです"IPositionalを実装するすべてのクラス

    関連する問題