Swiftでプロトコル型に対して===演算子を使いたい時の対処法

公開日: : 最終更新日:2016/02/10 iPhoneアプリ開発

20160204-120840.jpg

プロトコル型の変数や定数に対して===演算子を使うと「error: binary operator ‘===’ cannot be applied to two ‘プロトコル名’ operands」というエラーが出ることがありますが、その時の対処法について解説したいと思います。

    

スポンサード リンク

「===演算子」とは?

以下、詳解 Swift 改訂版からの引用です。

まだ説明のない演算子に「===」と「!==」があります。これは参照型の値であるクラスのインスタンスの実体が同一のものかどうかを調べるためのものです。

Swiftには、複数箇所から参照されているインスタンスが同一のものかどうかを調べるための演算子として「===」が用意されています。この演算子はインスタンスの値が等しいかどうか(同値性)ではなく、メモリ上にある同じインスタンスの実体を指しているかどうか(同一性)を調べます。

同一ではないことを調べる演算子は「!==」です。

    

コードを書いて確認してみましょう。

// Swiftにおいて、Stringはstruct(値型)、NSStringはclass(参照型)
let str1 = NSString(string: "hello")
let str2 = NSString(string: "hello")
let str3 = str1

str1 == str2 // true

str1 === str2 // false

str1 == str3 // true

str1 === str3 // true

str1とstr2は、文字の内容は同じですが、別インスタンスとなっています。

また、str3はstr1と同じインスタンスを参照しています。

    

プロトコル型の変数や定数に対して===演算子を使ってみる

では、プロトコル型の変数や定数に対して===演算子を使ってみましょう。

protocol PersonalProtocol {
    var name : String { get set }
}

class Person : PersonalProtocol {
    var name : String = ""
}

let personal1 : PersonalProtocol = Person()
let personal2 : PersonalProtocol = Person()

// error: binary operator '===' cannot be applied to two 'PersonalProtocol' operands
personal1 === personal2

===演算子を使っているところでエラーが出ています。

    

===演算子の定義について調べてみる

===演算子の定義について確認してみましょう。

public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool

引数として、2つのAnyObject?型を受け取っていますね。

以下、詳解 Swift 改訂版からの引用です。

継承関係がないクラスのインスタンス同士を何らかの都合で1つの型で表したい場合もあります。そのような場合、SwiftではAnyObjectという型を利用できます。

    

AnyObjectの定義についても調べてみましょう。

/// The protocol to which all classes implicitly conform.
@objc public protocol AnyObject {

「すべてのクラスが暗黙的に適合するプロトコル」と書かれていますね。

    

普通のプロトコル型の変数や定数にはstructのインスタンスも代入できるから、===演算子が使えない

以上のことを踏まえると、普通のプロトコル型の変数や定数にはstructのインスタンスも代入できるので、2つのAnyObject型の引数を受け取る===演算子をプロトコル型の変数や定数に対して使用することはできないということですね。

以下、実例を挙げてみます。

protocol PersonalProtocol {
    var name : String { get set }
}

class PersonClass : PersonalProtocol {
    var name : String = ""
}

struct PersonStruct : PersonalProtocol {
    var name : String = ""
}

let personal1 : PersonalProtocol = PersonClass()
let personal2 : PersonalProtocol = PersonStruct()

// error: binary operator '===' cannot be applied to two 'PersonalProtocol' operands
personal1 === personal2

    

structをAnyObjectに適合させてみる

では、structのほうをAnyObjectに適合させてみてはどうでしょうか?

実際にやってみます。

protocol PersonalProtocol {
    var name : String { get set }
}

class PersonClass : PersonalProtocol {
    var name : String = ""
}

// error: non-class type 'PersonStruct' cannot conform to class protocol 'AnyObject'
struct PersonStruct : PersonalProtocol, AnyObject {
    var name : String = ""
}

let personal1 : PersonalProtocol = PersonClass()
let personal2 : PersonalProtocol = PersonStruct()

// error: binary operator '===' cannot be applied to two 'PersonalProtocol' operands
personal1 === personal2

「error: non-class type ‘PersonStruct’ cannot conform to class protocol ‘AnyObject’」というエラーが出てしまいました。クラスではない型をAnyObjectプロトコルに適合させることはできないみたいです。

    

プロトコルをAnyObjectから継承させてみる

では、プロトコルをAnyObjectから継承させてみましょう。

protocol PersonalProtocol : AnyObject {
    var name : String { get set }
}

class PersonClass : PersonalProtocol {
    var name : String = ""
}

let personal1 : PersonalProtocol = PersonClass()
let personal2 : PersonalProtocol = PersonClass()

personal1 === personal2 // false

これでプロトコル型に対して===演算子を使えるようになりました。

なお、PersonalProtorolはAnyObjectを継承しているので、struct型をPersonalProtorolに適合させることはできなくなります。

protocol PersonalProtocol : AnyObject {
    var name : String { get set }
}

class PersonClass : PersonalProtocol {
    var name : String = ""
}

// error: non-class type 'PersonStruct' cannot conform to class protocol 'AnyObject'
struct PersonStruct : PersonalProtocol {
    var name : String = ""
}

    

プロトコルにclassキーワードを記述してもOK

また別の方法として、プロトコルにclassキーワードを記述してもOKみたいです。

以下、詳解 Swift 改訂版からの引用です。

プロトコルはクラス、構造体、列挙型で採用することができますが、値型よりも参照型のデータでの実装を前提としている場合や、継承を利用する場合など、クラスでの実装だけを想定してプロトコルを定義する場合があります。そのような場合、クラスだけが対象であることを明示するために、プロトコル名に続いてコロン「:」を置き、キーワードとしてclassと記述します。

実際にやってみましょう。

protocol PersonalProtocol : class {
    var name : String { get set }
}

class PersonClass : PersonalProtocol {
    var name : String = ""
}

let personal1 : PersonalProtocol = PersonClass()
let personal2 : PersonalProtocol = PersonClass()

personal1 === personal2 // false

===演算子が使えてますね。

    

ちなみにclassキーワードを付けたプロトコルは、AnyObjectプロトコルを継承している扱いになるようです。

protocol PersonalProtocol : class {
    var name : String { get set }
}

class PersonClass : PersonalProtocol {
    var name : String = ""
}

let personal1 : PersonalProtocol = PersonClass()

personal1 is AnyObject // true

    

@akio0911はこう思った。

エラーが出た時は「なんでプロトコルに===演算子が使えないの!?」と思ったのですが、いろいろと調べてみるときちんと筋の通った仕組みになっていることが分かりますね。

    

Swiftの細かい仕様について学ぶには、詳解 Swift 改訂版が便利です。

この記事が気に入ったら「いいね!」しよう

follow us in feedly

Feedlyで最新記事を購読

Twitterで更新情報をゲット!

LINEでご感想・ご要望お送りください!
(スマホでLINEを起動 > 友だち追加 > QRコード)

関連記事

20150108-113233.jpg

【Swift】コードをコンパクトに記述できるオプショナルチェーン(optional chaining)の性質と活用例

最近はSwiftでコーディングすることが多い@akio0911です。今日はSwiftでコード

記事を読む

20150410-122409.jpg

複数バージョンのXcodeを共存してMacにインストールする方法

いよいよXcode 6.3が正式にリリースされましたね。 今回は複数バージョンのXco

記事を読む

iPhoneゲームを簡単に開発したいならこの本がオススメ!「Sprite Kit iPhone 2Dゲームプログラミング」

iPhoneゲームアプリを簡単に開発したいなら「Sprite Kit iPhone 2Dゲームプ

記事を読む

エディタのショートカット・Auto Layout・ブレークポイントに関する詳しい解説も!「Xcode5徹底解説」

著者の@es_kumagaiさんより献本御礼。iOSアプリ開発に用いるツール「Xcode 5」の

記事を読む

20150525-224340.jpg

【Swift】クロージャをメソッドや関数の引数として渡す方法

Swiftでメソッドの引数としてクロージャを渡す方法について解説したいと思います。     

記事を読む

I20150714-010114.jpg

【Swift】Objective-Cで書いたクラスをメソッド単位で少しずつSwiftへ移行する方法

Objective-Cで作った既存のアプリをSwiftで書き直したいと思っているのですが、一

記事を読む

Auto LayoutやStoryboardの仕組みをしっかり理解できる!「UIKit徹底解説」

インプレスジャパン様より献本御礼。UIKit周りを中心に、「Auto Layout」「Story

記事を読む

20150116-114410.jpg

プログラミング未経験者がSwiftの文法を学ぶのにオススメな本!「たのしいSwiftプログラミング」

楽しみにしていたSwiftの入門書「たのしいSwiftプログラミング」を読み終わったので、レビュ

記事を読む

I20150808-104713.jpg

【Xcode】シミュレーターリストの表示がおかしくなった時の解決方法

Xcodeのシミュレーターリストの表示が、上のスクリーンショットのようにおかしくなってしまっ

記事を読む

I20160217-170931.jpg

2016年2月15日以降、Missing iOS Distribution Signing identity for XXX というエラーが出た場合の解決方法

2016年2月15日以降、AppStoreへの申請やipaファイルのエクスポートで「Missin

記事を読む

20170423-182541
良肌研究室のフェイスウォッシュとオールインワンジェルを使ってみた

株式会社ブラシナさんから、良肌研究室の商品をご提供頂いたので、

I20170228-002742.jpg
約3ヶ月で体脂肪率を6.2%も落とせたキッカケについて

(右上の赤枠内がダイエット開始前、左下の赤枠内が3ヶ月後の数値

I20161224-174949.jpg
「季節の野菜を直接配送!季節のスムージー」を買ってみた

「FiNCモール」で、「季節の野菜を直接配送!季節のスムージー」を

I20161002-152537.jpg
【メンズネイル】東京・新宿のネイルサロンでマットネイルしてもらった

2016年7月18日、東京・新宿のメンズOKなネイルサロン「Tot

I20160925-163452.jpg
タブバーアイコン非選択時の色を変更する方法【iOS 10】

UITabBarControllerで、タブバーアイコン非選択時の

→もっと見る

PAGE TOP ↑