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コード)

関連記事

20160508-170745.jpg

SwiftTaskで失敗したタスクによって異なるエラー処理を行う方法

SwiftTaskで複数のタスクを.successでチェーンさせ、失敗したタスクによって

記事を読む

20150522-105524.jpg

【書籍】初心者にオススメな本!「これからはじめる Apple Watchアプリ開発入門」

Apple Watchは買いましたか?使ってますか?アプリを作ってみたくはないですか? という

記事を読む

I20160128-101452.jpg

【解決】Playground execution terminated because the process stopped unexpectedlyが出た時の対処法

Xcodeのプレイグラウンドで「Playground execution terminated

記事を読む

20160724-154909.jpg

デザインの素人がノンデザイナーズ・デザインブックを読んだら、デザインの原則が結構分かるようになった!

ずっとエンジニアとして働いてきてデザインに関してはまったくの素人な僕ですが、「ノンデザイナーズ・

記事を読む

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

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

記事を読む

I20150909-225806.jpg

Functional Programming in Swiftを読むために、すごいH本を読み終えた感想

「Functional Programming in Swift」という本がありまして、

記事を読む

I20151030-214417.jpg

【開発本】SpriteKitの入門書籍「iPhoneのゲームアプリをつくろう!」

SwiftとSpriteKitでiPhoneゲームアプリを開発するための入門書「iPhone

記事を読む

I20160125-104438.jpg

iPhoneアプリの開発に必要なものをまとめてみた

僕はアプリ開発講座を開催していますが、その関係もあって「iPhoneアプリを開発するには、ど

記事を読む

20140810-193043.jpg

WordPressでObjective-Cのソースコードをキレイに整形して表示する方法

WordPressの記事内で、Objective-Cのソースコードをキレイに整形して表示する方法

記事を読む

I20151126-170621.jpg

Swift 2のprintで改行しない方法

Swift 1時代はprintlnで改行あり、printで改行なしでしたが、Swift 2ではp

記事を読む

I20170521-225453.jpg
東京駅八重洲口の「羊肉酒場 悟大」で網焼きジンギスカンを頂きました!

ゆうせいさんと株式会社 大庄さんからご招待頂き、悟大withサッポ

I20170514-165235.jpg
iPhoneと連携できる体重体組成計「Withings Body Cardio」を使ってます

ジムに通い始めて体脂肪率が落ち始めたのをキッカケに、iPhoneと

I20170507-155440.jpg
【派手髪】ハーレイクイン風の髪色に染めてもらいました

2016年10月20日、ハーレイクイン風の髪色に染めてもらいました

I20170504-173110.jpg
【メンズネイル】東京・新宿のネイルサロンでターコイズのホログラムネイルしてもらった

ネイルネタが1年分くらい溜まっているので、ちょっとずつ書いていこう

I20170502-010117.jpg
SNUGGのライトニングケーブルが耐久性高し。8ヶ月使ってますが断線の気配なし!

iPhoneの充電&転送ケーブルであるLightningケーブルっ

→もっと見る

PAGE TOP ↑