プロトコル
日本語を消す 英語を消す下記URLから引用し、日本語訳をつけてみました。
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols
Define requirements that conforming types must implement.
適合する型が実装する必要がある要件を定義します。
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.
プロトコルは、特定のタスクや機能に適したメソッド、プロパティ、その他の要件の設計図を定義します。 その後、プロトコルをクラス、構造、または列挙で採用して、これらの要件の実際の実装を提供できます。 プロトコルの要件を満たす型は、そのプロトコルに準拠していると言われます。
In addition to specifying requirements that conforming types must implement, you can extend a protocol to implement some of these requirements or to implement additional functionality that conforming types can take advantage of.
適合型が実装する必要がある要件を指定することに加えて、プロトコルを拡張して、これらの要件の一部を実装したり、適合型が利用できる追加機能を実装したりできます。
Protocol Syntax
プロトコル構文
You define protocols in a very similar way to classes, structures, and enumerations:
プロトコルは、クラス、構造体、列挙型と非常によく似た方法で定義します。
protocol SomeProtocol {
// protocol definition goes here
}
Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas:
カスタム型は、その定義の一部として、型名の後にコロンで区切ってプロトコル名を配置することで、特定のプロトコルを採用していることを示します。 複数のプロトコルをリストすることができ、カンマで区切ります。
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma:
クラスにスーパークラスがある場合は、そのクラスが採用するプロトコルの前にスーパークラス名をリストし、その後にカンマを続けます。
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// class definition goes here
}
Note
注釈
Because protocols are types, begin their names with a capital letter (such as FullyNamed
and RandomNumberGenerator
) to match the names of other types in Swift (such as Int
, String
, and Double
).
プロトコルは型であるため、Swift の他の型(Int
、String
、Double
など)の名前と一致するように、名前を大文字で始めます(FullyNamed
や RandomNumberGenerator
など)。
Property Requirements
プロパティの要件
A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property — it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable.
プロトコルでは、特定の名前と型を持つインスタンス プロパティまたは型プロパティを提供するために、任意の準拠型を要求できます。 このプロトコルでは、プロパティが保存されたプロパティであるべきか、計算されたプロパティであるべきかは指定されておらず、必要なプロパティの名前と型のみが指定されています。 このプロトコルでは、各プロパティが取得可能である必要があるか、取得可能かつ設定可能である必要があるかどうかも指定されます。
If a protocol requires a property to be gettable and settable, that property requirement can’t be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it’s valid for the property to be also settable if this is useful for your own code.
プロトコルでプロパティが取得可能および設定可能であることが必要な場合、そのプロパティ要件は、定数の保存プロパティや読み取り専用の計算プロパティでは満たすことができません。 プロトコルがプロパティを取得可能にすることのみを要求する場合、その要件はどのような種類のプロパティでも満たすことができ、独自のコードに役立つ場合にはプロパティを設定可能にすることも有効です。
Property requirements are always declared as variable properties, prefixed with the var
keyword. Gettable and settable properties are indicated by writing { get set }
after their type declaration, and gettable properties are indicated by writing { get }
.
プロパティ要件は常に、var
キーワードを接頭辞として付けた変数プロパティとして宣言されます。 取得可能および設定可能なプロパティは、型宣言の後に { get set }
を記述することで示され、取得可能なプロパティは { get }
を記述することで示されます。
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
Always prefix type property requirements with the static
keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class
or static
keyword when implemented by a class:
プロトコルで型 プロパティ要件を定義する場合は、必ずその要件の前に static
キーワードを付けます。 このルールは、クラスによって実装される場合、型 プロパティ要件の前に class
または static
キーワードを付けることができる場合にも当てはまります。
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
Here’s an example of a protocol with a single instance property requirement:
単一インスタンスのプロパティ要件を持つプロトコルの例を次に示します。
protocol FullyNamed {
var fullName: String { get }
}
The FullyNamed
protocol requires a conforming type to provide a fully qualified name. The protocol doesn’t specify anything else about the nature of the conforming type — it only specifies that the type must be able to provide a full name for itself. The protocol states that any FullyNamed
type must have a gettable instance property called fullName
, which is of type String
.
FullyNamed
プロトコルでは、完全修飾名を提供するために適合する型が必要です。 このプロトコルは、適合する型の性質については何も指定していません。型がそれ自体の完全な名前を提供できる必要があることだけを指定しています。 このプロトコルでは、FullyNamed
型には、string
型の fullName
という取得可能なインスタンス プロパティが必要であると規定されています。
Here’s an example of a simple structure that adopts and conforms to the FullyNamed
protocol:
FullyNamed
プロトコルを採用し準拠する単純な構造の例を次に示します。
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed"
This example defines a structure called Person
, which represents a specific named person. It states that it adopts the FullyNamed
protocol as part of the first line of its definition.
この例では、特定の名前付き人物を表す Person
という構造を定義します。 定義の最初の行の一部として FullyNamed
プロトコルを採用していると記載されています。
Each instance of Person
has a single stored property called fullName
, which is of type String
. This matches the single requirement of the FullyNamed
protocol, and means that Person
has correctly conformed to the protocol. (Swift reports an error at compile time if a protocol requirement isn’t fulfilled.)
Person
の各インスタンスには、fullName
という名前の String
型の保存プロパティが 1 つあります。 これは、FullyNamed
プロトコルの 1 つの要件と一致しており、ユーザーがプロトコルに正しく準拠していることを意味します。 (プロトコル要件が満たされていない場合、Swift はコンパイル時にエラーを報告します。)
Here’s a more complex class, which also adopts and conforms to the FullyNamed
protocol:
以下は、FullyNamed
プロトコルを採用して準拠する、より複雑なクラスです。
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName is "USS Enterprise"
This class implements the fullName
property requirement as a computed read-only property for a starship. Each Starship
class instance stores a mandatory name
and an optional prefix
. The fullName
property uses the prefix
value if it exists, and prepends it to the beginning of name
to create a full name for the starship.
このクラスは、宇宙船の計算された読み取り専用プロパティとして fullName
プロパティ要件を実装します。 各 Starship
クラス インスタンスには、必須のname
とオプションのprefix
が保存されます。 fullName
プロパティは、prefix
値が存在する場合はそれを使用し、それをname
の先頭に付加して宇宙船のフルネームを作成します。
Method Requirements
メソッドの要件
Protocols can require specific instance methods and type methods to be implemented by conforming types. These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. Default values, however, can’t be specified for method parameters within a protocol’s definition.
プロトコルでは、特定のインスタンス メソッドと型メソッドを、準拠する型によって実装する必要がある場合があります。 これらのメソッドは、通常のインスタンス メソッドや型メソッドとまったく同じ方法でプロトコル定義の一部として記述されますが、中かっこやメソッド本体は使用されません。 可変引数パラメーターは、通常のメソッドと同じルールに従って許可されます。 ただし、プロトコル定義内のメソッド パラメータにデフォルト値を指定することはできません。
As with type property requirements, you always prefix type method requirements with the static
keyword when they’re defined in a protocol. This is true even though type method requirements are prefixed with the class
or static
keyword when implemented by a class:
型 プロパティの要件と同様、プロトコルで定義する場合は、型 メソッドの要件の前に常に static
キーワードを付けます。 これは、クラスによって実装される場合、型メソッドの要件に class
または static
キーワードがプレフィックスとして付けられる場合でも当てはまります。
protocol SomeProtocol {
static func someTypeMethod()
}
The following example defines a protocol with a single instance method requirement:
次の例では、単一インスタンス メソッド要件を持つプロトコルを定義します。
protocol RandomNumberGenerator {
func random() -> Double
}
This protocol, RandomNumberGenerator
, requires any conforming type to have an instance method called random
, which returns a Double
value whenever it’s called. Although it’s not specified as part of the protocol, it’s assumed that this value will be a number from 0.0
up to (but not including) 1.0
.
このプロトコル、RandomNumberGenerator
では、準拠する型に、呼び出されるたびに Double
値を返す、random
と呼ばれるインスタンス メソッドが必要です。 プロトコルの一部として指定されていませんが、この値は 0.0
から 1.0
までの数値であると想定されます(ただし、1.0 は含まれません)。
The RandomNumberGenerator
protocol doesn’t make any assumptions about how each random number will be generated — it simply requires the generator to provide a standard way to generate a new random number.
RandomNumberGenerator
プロトコルは、各乱数がどのように生成されるかについて何も想定しません。単に、ジェネレーターが新しい乱数を生成する標準的な方法を提供することを要求します。
Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator
protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator:
以下は、RandomNumberGenerator プロトコルを採用し、準拠するクラスの実装です。 このクラスは、線形合同生成器として知られる擬似乱数生成アルゴリズムを実装します。
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c)
.truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Prints "Here's a random number: 0.3746499199817101"
print("And another one: \(generator.random())")
// Prints "And another one: 0.729023776863283"
Mutating Method Requirements
変更メソッドの要件
It’s sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating
keyword before a method’s func
keyword to indicate that the method is allowed to modify the instance it belongs to and any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods.
メソッドが属するインスタンスを変更(または変異)することが必要になる場合があります。 たとえば、値の型(つまり、構造体と列挙型)のメソッドでは、メソッドの func
キーワードの前に mutating
キーワードを配置して、そのメソッドが属するインスタンスとそのインスタンスのプロパティを変更できることを示します。 このプロセスについては、「インスタンス メソッド内からの値の型の変更」で説明されています。
If you define a protocol instance method requirement that’s intended to mutate instances of any type that adopts the protocol, mark the method with the mutating
keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement.
プロトコルを採用する任意の型のインスタンスを変更することを目的としたプロトコル インスタンス メソッド要件を定義する場合は、プロトコル定義の一部としてメソッドに mutating
キーワードをマークします。 これにより、構造体と列挙型がプロトコルを採用し、そのメソッドの要件を満たすことが可能になります。
Note
注釈
If you mark a protocol instance method requirement as mutating
, you don’t need to write the mutating
keyword when writing an implementation of that method for a class. The mutating
keyword is only used by structures and enumerations.
プロトコル インスタンス メソッドの要件をmutating
としてマークすると、クラスのそのメソッドの実装を記述するときにmutating
キーワードを記述する必要がなくなります。 mutating
キーワードは、構造体と列挙型でのみ使用されます。
The example below defines a protocol called Togglable
, which defines a single instance method requirement called toggle
. As its name suggests, the toggle()
method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type.
以下の例では、Toggleable
というプロトコルを定義し、toggle
という単一インスタンス メソッドの要件を定義しています。 その名前が示すように、toggle()
メソッドは、通常、その型のプロパティを変更することによって、準拠する型の状態を切り替えるか反転することを目的としています。
The toggle()
method is marked with the mutating
keyword as part of the Togglable
protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it’s called:
toggle()
メソッドには、Togglable
プロトコル定義の一部として mutating
キーワードがマークされており、メソッドが呼び出されたときに準拠するインスタンスの状態を変更することが期待されていることを示します。
protocol Togglable {
mutating func toggle()
}
If you implement the Togglable
protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle()
method that’s also marked as mutating
.
構造体または列挙型に Togglable
プロトコルを実装する場合、その構造体または列挙型は、変更可能としてマークされている toggle()
メソッドの実装を提供することでプロトコルに準拠できます。
The example below defines an enumeration called OnOffSwitch
. This enumeration toggles between two states, indicated by the enumeration cases on
and off
. The enumeration’s toggle
implementation is marked as mutating
, to match the Togglable
protocol’s requirements:
以下の例では、OnOffSwitch
という列挙を定義しています。 この列挙は、列挙ケースのon
とoff
で示される 2 つの状態を切り替えます。 列挙型のtoggle
実装は、Togglable
プロトコルの要件に一致するように、mutating
としてマークされます。
enum OnOffSwitch: Togglable {
case off, on
mutating func toggle() {
switch self {
case .off:
self = .on
case .on:
self = .off
}
}
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
// lightSwitch is now equal to .on
Initializer Requirements
イニシャライザの要件
Protocols can require specific initializers to be implemented by conforming types. You write these initializers as part of the protocol’s definition in exactly the same way as for normal initializers, but without curly braces or an initializer body:
プロトコルでは、適合する型によって特定のイニシャライザを実装することが必要になる場合があります。 これらのイニシャライザは、通常のイニシャライザとまったく同じ方法でプロトコル定義の一部として記述しますが、中括弧やイニシャライザ本体は使用しません。
protocol SomeProtocol {
init(someParameter: Int)
}
Class Implementations of Protocol Initializer Requirements
プロトコル初期化子要件のクラス実装
You can implement a protocol initializer requirement on a conforming class as either a designated initializer or a convenience initializer. In both cases, you must mark the initializer implementation with the required
modifier:
プロトコル初期化子要件は、指定された初期化子またはコンビニエンス初期化子のいずれかとして、準拠クラスに実装できます。 どちらの場合も、イニシャライザ実装をrequired
修飾子でマークする必要があります。
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
The use of the required
modifier ensures that you provide an explicit or inherited implementation of the initializer requirement on all subclasses of the conforming class, such that they also conform to the protocol.
required
修飾子を使用すると、準拠クラスのすべてのサブクラスにイニシャライザ要件の明示的または継承された実装が提供され、プロトコルにも準拠するようになります。
For more information on required initializers, see Required Initializers.
必要なイニシャライザの詳細については、「必要なイニシャライザ」を参照してください。
Note
注釈
You don’t need to mark protocol initializer implementations with the required
modifier on classes that are marked with the final
modifier, because final classes can’t subclassed. For more about the final
modifier, see Preventing Overrides.
final
修飾子でマークされたクラスでは、プロトコル初期化子の実装をrequired
修飾子でマークする必要はありません。final
クラスはサブクラス化できないためです。 final
修飾子の詳細については、「オーバーライドの防止」を参照してください。
If a subclass overrides a designated initializer from a superclass, and also implements a matching initializer requirement from a protocol, mark the initializer implementation with both the required
and override
modifiers:
サブクラスがスーパークラスから指定されたイニシャライザをオーバーライドし、プロトコルから一致するイニシャライザ要件も実装する場合は、イニシャライザ実装をrequired
修飾子とoverride
修飾子の両方でマークします。
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}
Failable Initializer Requirements
失敗可能なイニシャライザの要件
Protocols can define failable initializer requirements for conforming types, as defined in Failable Initializers.
「Failable Initializers」で定義されているように、プロトコルでは、準拠する型の failable イニシャライザ要件を定義できます。
A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type. A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.
失敗可能なイニシャライザの要件は、適合する型の失敗可能なイニシャライザまたは失敗しないイニシャライザによって満たされます。 失敗しないイニシャライザの要件は、失敗しないイニシャライザまたは暗黙的にアンラップされた失敗可能なイニシャライザによって満たされます。
Protocols as Types
型としてのプロトコル
Protocols don’t actually implement any functionality themselves. Regardless, you can use a protocol as a type in your code.
プロトコル自体は実際には機能を実装しません。 いずれにしても、コード内の型としてプロトコルを使用できます。
The most common way to use a protocol as a type is to use a protocol as a generic constraint. Code with generic constraints can work with any type that conforms to the protocol, and the specific type is chosen by the code that uses the API. For example, when you call a function that takes an argument and that argument’s type is generic, the caller chooses the type.
プロトコルを型として使用する最も一般的な方法は、プロトコルを汎用制約として使用することです。 汎用制約のあるコードは、プロトコルに準拠する任意の型で動作でき、特定の型は API を使用するコードによって選択されます。 たとえば、引数を受け取る関数を呼び出し、その引数の型がジェネリックである場合、呼び出し元が型を選択します。
Code with an opaque type works with some type that conforms to the protocol. The underlying type is known at compile time, and the API implementation chooses that type, but that type’s identity is hidden from clients of the API. Using an opaque type lets you prevent implementation details of an API from leaking through the layer of abstraction — for example, by hiding the specific return type from a function, and only guaranteeing that the value conforms to a given protocol.
不透明型のコードは、プロトコルに準拠する何らかの型で動作します。 基礎となる型はコンパイル時に判明し、API 実装はその型を選択しますが、その型の ID は API のクライアントから隠されます。 不透明型を使用すると、API の実装の詳細が抽象化レイヤーを介して漏洩するのを防ぐことができます。たとえば、関数から特定の戻り値の型を隠し、値が指定されたプロトコルに準拠していることのみを保証します。
Code with a boxed protocol type works with any type, chosen at runtime, that conforms to the protocol. To support this runtime flexibility, Swift adds a level of indirection when necessary — known as a box, which has a performance cost. Because of this flexibility, Swift doesn’t know the underlying type at compile time, which means you can access only the members that are required by the protocol. Accessing any other APIs on the underlying type requires casting at runtime.
ボックス化されたプロトコル 型のコードは、実行時に選択された、プロトコルに準拠する任意の型で機能します。 この実行時の柔軟性をサポートするために、Swift は必要に応じてボックスと呼ばれる間接レベルを追加しますが、これにはパフォーマンス コストがかかります。 この柔軟性により、Swift はコンパイル時に基になる型を認識しません。つまり、プロトコルで必要なメンバーのみにアクセスできます。 基になる型の他の API にアクセスするには、実行時にキャストする必要があります。
For information about using protocols as generic constraints, see Generics. For information about opaque types, and boxed protocol types, see Opaque and Boxed Types.
一般的な制約としてプロトコルを使用する方法については、「一般」を参照してください。 不透明な型とボックス化されたプロトコルの型については、「不透明な型とボックス化された型」を参照してください。
Delegation
委任
Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source.
委任は、クラスまたは構造がその責任の一部を別の型のインスタンスに引き渡す (または委任する) ことを可能にする設計パターンです。 この設計パターンは、委任された責任をカプセル化するプロトコルを定義することによって実装され、準拠する型 (デリゲートと呼ばれる) が委任された機能を提供することが保証されます。 委任を使用すると、特定のアクションに応答したり、外部ソースの基礎となる型を知らなくてもそのソースからデータを取得したりできます。
The example below defines a dice game and a nested protocol for a delegate that tracks the game’s progress:
以下の例では、サイコロ ゲームと、ゲームの進行状況を追跡するデリゲートのネストされたプロトコルを定義しています。
class DiceGame {
let sides: Int
let generator = LinearCongruentialGenerator()
weak var delegate: Delegate?
init(sides: Int) {
self.sides = sides
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
func play(rounds: Int) {
delegate?.gameDidStart(self)
for round in 1...rounds {
let player1 = roll()
let player2 = roll()
if player1 == player2 {
delegate?.game(self, didEndRound: round, winner: nil)
} else if player1 > player2 {
delegate?.game(self, didEndRound: round, winner: 1)
} else {
delegate?.game(self, didEndRound: round, winner: 2)
}
}
delegate?.gameDidEnd(self)
}
protocol Delegate: AnyObject {
func gameDidStart(_ game: DiceGame)
func game(_ game: DiceGame, didEndRound round: Int, winner: Int?)
func gameDidEnd(_ game: DiceGame)
}
}
The DiceGame
class implements a game where each player takes a turn rolling dice, and the player who rolls the highest number wins the round. It uses a linear congruential generator from the example earlier in the chapter, to generate random numbers for dice rolls.
DiceGame
クラスは、各プレイヤーが順番にサイコロを振り、最も高い数字を振ったプレイヤーがラウンドに勝つゲームを実装します。 この章の前半の例で示した線形合同ジェネレーターを使用して、サイコロの目の乱数を生成します。
The DiceGame.Delegate
protocol can be adopted to track the progress of a dice game. Because the DiceGame.Delegate
protocol is always used in the context of a dice game, it’s nested inside of the DiceGame
class. Protocols can be nested inside of type declarations like structures and classes, as long as the outer declaration isn’t generic. For information about nesting types, see Nested Types.
DiceGame.Delegate
プロトコルは、サイコロ ゲームの進行状況を追跡するために採用できます。 DiceGame.Delegate
プロトコルは常にサイコロ ゲームのコンテキストで使用されるため、DiceGame
クラス内にネストされています。 プロトコルは、外側の宣言がジェネリックでない限り、構造体やクラスなどの型宣言の内側にネストできます。 ネスト型の詳細については、「ネストされた型」を参照してください。
To prevent strong reference cycles, delegates are declared as weak references. For information about weak references, see Strong Reference Cycles Between Class Instances. Marking the protocol as class-only lets the DiceGame
class declare that its delegate must use a weak reference. A class-only protocol is marked by its inheritance from AnyObject
, as discussed in Class-Only Protocols.
強参照の循環を防ぐために、デリゲートは弱参照として宣言されます。 弱参照の詳細については、「クラス インスタンス間の強参照サイクル」を参照してください。 プロトコルをクラス専用としてマークすると、DiceGame
クラスはそのデリゲートが弱い参照を使用する必要があることを宣言できます。 クラス専用プロトコルは、「クラス専用プロトコル」で説明されているように、AnyObject
からの継承によってマークされます。
DiceGame.Delegate
provides three methods for tracking the progress of a game. These three methods are incorporated into the game logic in the play(rounds:)
method above. The DiceGame
class calls its delegate methods when a new game starts, a new turn begins, or the game ends.
DiceGame.Delegate
は、ゲームの進行状況を追跡するための 3 つのメソッドを提供します。 これら 3 つのメソッドは、上記の play(rounds:)
メソッドのゲーム ロジックに組み込まれています。 DiceGame
クラスは、新しいゲームの開始時、新しいターンの開始時、またはゲームの終了時にそのデリゲート メソッドを呼び出します。
Because the delegate
property is an optional DiceGame.Delegate
, the play(rounds:)
method uses optional chaining each time it calls a method on the delegate, as discussed in Optional Chaining. If the delegate
property is nil, these delegate calls are ignored. If the delegate
property is non-nil, the delegate methods are called, and are passed the DiceGame
instance as a parameter.
delegate
プロパティはオプションの DiceGame.Delegate
であるため、「オプションのチェーン」で説明したように、play(rounds:)
メソッドはデリゲートのメソッドを呼び出すたびにオプションのチェーンを使用します。 delegate
プロパティが nil の場合、これらのデリゲート呼び出しは無視されます。 delegate
プロパティが非 nil
の場合、デリゲート メソッドが呼び出され、DiceGame
インスタンスがパラメータとして渡されます。
This next example shows a class called DiceGameTracker
, which adopts the DiceGame.Delegate
protocol:
次の例は、DiceGame.Delegate
プロトコルを採用する DiceGameTracker
というクラスを示しています。
class DiceGameTracker: DiceGame.Delegate {
var playerScore1 = 0
var playerScore2 = 0
func gameDidStart(_ game: DiceGame) {
print("Started a new game")
playerScore1 = 0
playerScore2 = 0
}
func game(_ game: DiceGame, didEndRound round: Int, winner: Int?) {
switch winner {
case 1:
playerScore1 += 1
print("Player 1 won round \(round)")
case 2: playerScore2 += 1
print("Player 2 won round \(round)")
default:
print("The round was a draw")
}
}
func gameDidEnd(_ game: DiceGame) {
if playerScore1 == playerScore2 {
print("The game ended in a draw.")
} else if playerScore1 > playerScore2 {
print("Player 1 won!")
} else {
print("Player 2 won!")
}
}
}
The DiceGameTracker
class implements all three methods that are required by the DiceGame.Delegate
protocol. It uses these methods to zero out both players’ scores at the start of a new game, to update their scores at the end of each round, and to announce a winner at the end of the game.
DiceGameTracker
クラスは、DiceGame.Delegate
プロトコルで必要な 3 つのメソッドをすべて実装します。 これらのメソッドを使用して、新しいゲームの開始時に両方のプレーヤーのスコアをゼロにし、各ラウンドの終了時にスコアを更新し、ゲームの終了時に勝者を発表します。
Here’s how DiceGame
and DiceGameTracker
look in action:
DiceGame と DiceGameTracker が動作している様子は次のとおりです。
let tracker = DiceGameTracker()
let game = DiceGame(sides: 6)
game.delegate = tracker
game.play(rounds: 3)
// Started a new game
// Player 2 won round 1
// Player 2 won round 2
// Player 1 won round 3
// Player 2 won!
Adding Protocol Conformance with an Extension
拡張機能によるプロトコル準拠の追加
You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions.
既存の型のソース コードにアクセスできない場合でも、既存の型を拡張して新しいプロトコルを採用し、準拠させることができます。 拡張機能は、既存の型に新しいプロパティ、メソッド、添字を追加できるため、プロトコルが要求するあらゆる要件を追加できます。 拡張機能の詳細については、「拡張機能」をご覧ください。
Note
注釈
Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension.
型の既存のインスタンスは、拡張機能でインスタンスの型に準拠が追加されると、プロトコルを自動的に採用して準拠します。
For example, this protocol, called TextRepresentable
, can be implemented by any type that has a way to be represented as text. This might be a description of itself, or a text version of its current state:
たとえば、TextRepresentable
と呼ばれるこのプロトコルは、テキストとして表現する方法を持つ任意の型で実装できます。 これは、それ自体の説明、または現在の状態のテキスト バージョンである可能性があります。
protocol TextRepresentable {
var textualDescription: String { get }
}
The Dice
class from above can be extended to adopt and conform to TextRepresentable
:
上記の Dice
クラスは、TextRepresentable
を採用して準拠するように拡張できます。
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
This extension adopts the new protocol in exactly the same way as if Dice
had provided it in its original implementation. The protocol name is provided after the type name, separated by a colon, and an implementation of all requirements of the protocol is provided within the extension’s curly braces.
この拡張機能は、Dice
が元の実装で提供したのとまったく同じ方法で新しいプロトコルを採用します。 プロトコル名は型名の後にコロンで区切って指定され、プロトコルのすべての要件の実装は拡張機能の中括弧内に指定されます。
Any Dice
instance can now be treated as TextRepresentable
:
すべての Dice
インスタンスを TextRepresentable
として扱うことができるようになりました。
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription)
// Prints "A 12-sided dice"
Similarly, the SnakesAndLadders
game class can be extended to adopt and conform to the TextRepresentable
protocol:
同様に、SnakesAndLadders
ゲーム クラスは、TextRepresentable
プロトコルを採用して準拠するように拡張できます。
extension SnakesAndLadders: TextRepresentable {
var textualDescription: String {
return "A game of Snakes and Ladders with \(finalSquare) squares"
}
}
print(game.textualDescription)
// Prints "A game of Snakes and Ladders with 25 squares"
Conditionally Conforming to a Protocol
プロトコルへの条件付き準拠
A generic type may be able to satisfy the requirements of a protocol only under certain conditions, such as when the type’s generic parameter conforms to the protocol. You can make a generic type conditionally conform to a protocol by listing constraints when extending the type. Write these constraints after the name of the protocol you’re adopting by writing a generic where
clause. For more about generic where
clauses, see Generic Where Clauses.
ジェネリック型は、型のジェネリック パラメーターがプロトコルに準拠している場合など、特定の条件下でのみプロトコルの要件を満たすことができる場合があります。 型を拡張するときに制約をリストすることで、ジェネリック型を条件付きでプロトコルに準拠させることができます。 これらの制約は、採用するプロトコル名の後に一般的な where
句を記述して記述します。 一般的な Where
句の詳細については、「汎用Where 句」を参照してください。
The following extension makes Array
instances conform to the TextRepresentable
protocol whenever they store elements of a type that conforms to TextRepresentable
.
次の拡張機能は、Array
インスタンスが TextRepresentable
に準拠する型の要素を保存するときは常に、TextRepresentable
プロトコルに準拠するようにします。
extension Array: TextRepresentable where Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// Prints "[A 6-sided dice, A 12-sided dice]"
Declaring Protocol Adoption with an Extension
拡張機能を使用したプロトコル採用の宣言
If a type already conforms to all of the requirements of a protocol, but hasn’t yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension:
型がプロトコルのすべての要件にすでに準拠しているが、そのプロトコルを採用することをまだ表明していない場合は、空の拡張を付けてそのプロトコルを採用させることができます。
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
Instances of Hamster
can now be used wherever TextRepresentable
is the required type:
Hamster
のインスタンスは、TextRepresentable
が必要な型であればどこでも使用できるようになりました。
let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)
// Prints "A hamster named Simon"
Note
注釈
Types don’t automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol.
型は、要件を満たすだけではプロトコルを自動的に採用しません。 彼らは常にプロトコルの採用を明示的に宣言する必要があります。
Adopting a Protocol Using a Synthesized Implementation
合成された実装を使用したプロトコルの導入
Swift can automatically provide the protocol conformance for Equatable
, Hashable
, and Comparable
in many simple cases. Using this synthesized implementation means you don’t have to write repetitive boilerplate code to implement the protocol requirements yourself.
Swift は、多くの単純なケースにおいて、Equatable
、Hashable
、Comparable
のプロトコル準拠を自動的に提供できます。 この合成された実装を使用すると、プロトコル要件を自分で実装するために反復的な定型コードを作成する必要がなくなります。
Swift provides a synthesized implementation of Equatable
for the following kinds of custom types:
Swift は、次の種類のカスタム 型に対して Equatable
の合成実装を提供します。
- Structures that have only stored properties that conform to the
Equatable
protocol Equatable
プロトコルに準拠するプロパティのみを格納した構造- Enumerations that have only associated types that conform to the
Equatable
protocol Equatable
プロトコルに準拠する型のみが関連付けられている列挙型- Enumerations that have no associated types
- 関連する型を持たない列挙型
To receive a synthesized implementation of ==
, declare conformance to Equatable
in the file that contains the original declaration, without implementing an ==
operator yourself. The Equatable
protocol provides a default implementation of !=
.
==
の合成された実装を受け取るには、==
演算子を自分で実装せずに、元の宣言を含むファイルで Equatable
への準拠を宣言します。 Equatable
プロトコルは、!=
のデフォルト実装を提供します。
The example below defines a Vector3D
structure for a three-dimensional position vector (x, y, z)
, similar to the Vector2D
structure. Because the x
, y
, and z
properties are all of an Equatable
type, Vector3D
receives synthesized implementations of the equivalence operators.
以下の例では、Vector2D
構造と同様に、3 次元位置ベクトル (x、y、z)
の Vector3D
構造を定義します。 x、y、z
プロパティはすべて Equatable
型であるため、Vector3D
は等価演算子の合成された実装を受け取ります。
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
// Prints "These two vectors are also equivalent."
Swift provides a synthesized implementation of Hashable
for the following kinds of custom types:
Swift は、次の種類のカスタム 型に対して Hashable
の合成された実装を提供します。
- Structures that have only stored properties that conform to the
Hashable
protocol Hashable
プロトコルに準拠するプロパティのみを格納した構造- Enumerations that have only associated types that conform to the
Hashable
protocol Hashable
プロトコルに準拠する型のみが関連付けられた列挙型- Enumerations that have no associated types
- 関連する型を持たない列挙型
To receive a synthesized implementation of hash(into:)
, declare conformance to Hashable
in the file that contains the original declaration, without implementing a hash(into:)
method yourself.
hash(into:)
の合成された実装を受け取るには、hash(into:)
メソッドを自分で実装せずに、元の宣言を含むファイルで Hashable
への準拠を宣言します。
Swift provides a synthesized implementation of Comparable
for enumerations that don’t have a raw value. If the enumeration has associated types, they must all conform to the Comparable
protocol. To receive a synthesized implementation of <
, declare conformance to Comparable
in the file that contains the original enumeration declaration, without implementing a <
operator yourself. The Comparable
protocol’s default implementation of <=
, >
, and >=
provides the remaining comparison operators.
Swift は、生の値を持たない列挙型に対して Comparable
の合成実装を提供します。 列挙に関連付けられた型がある場合、それらはすべて Comparable
プロトコルに準拠する必要があります。 <
の合成された実装を受け取るには、<
演算子を自分で実装せずに、元の列挙宣言を含むファイルで Comparable
への準拠を宣言します。 Comparable
プロトコルのデフォルト実装である <=、>、>=
は、残りの比較演算子を提供します。
The example below defines a SkillLevel
enumeration with cases for beginners, intermediates, and experts. Experts are additionally ranked by the number of stars they have.
以下の例では、初心者、中級者、専門家向けのケースを含む SkillLevel
列挙を定義しています。 さらに、エキスパートは星の数によってランク付けされます。
enum SkillLevel: Comparable {
case beginner
case intermediate
case expert(stars: Int)
}
var levels = [SkillLevel.intermediate, SkillLevel.beginner,
SkillLevel.expert(stars: 5), SkillLevel.expert(stars: 3)]
for level in levels.sorted() {
print(level)
}
// Prints "beginner"
// Prints "intermediate"
// Prints "expert(stars: 3)"
// Prints "expert(stars: 5)"
Collections of Protocol Types
プロトコル型のコレクション
A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable
things:
「型としてのプロトコル」で説明したように、プロトコルは、配列や辞書などのコレクションに保存される型として使用できます。 この例では、TextRepresentable
の配列を作成します。
let things: [TextRepresentable] = [game, d12, simonTheHamster]
It’s now possible to iterate over the items in the array, and print each item’s textual description:
配列内の項目を反復処理し、各項目のテキストによる説明を出力できるようになりました。
for thing in things {
print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon
Note that the thing
constant is of type TextRepresentable
. It’s not of type Dice
, or DiceGame
, or Hamster
, even if the actual instance behind the scenes is of one of those types. Nonetheless, because it’s of type TextRepresentable
, and anything that’s TextRepresentable
is known to have a textualDescription
property, it’s safe to access thing.textualDescription
each time through the loop.
thing
定数の型は TextRepresentable
であることに注意してください。 たとえバックグラウンドの実際のインスタンスがこれらの型のいずれかであっても、それは型 Dice
、DiceGame
、または Hamster
ではありません。 それにもかかわらず、これは TextRepresentable
型であり、TextRepresentable
であるものはすべて textualDescription
プロパティを持つことが知られているため、ループを通じて毎回 Thing.textualDescription
に安全にアクセスできます。
Protocol Inheritance
プロトコルの継承
A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas:
プロトコルは、1 つ以上の他のプロトコルを継承でき、継承した要件にさらに要件を追加できます。 プロトコル継承の構文はクラス継承の構文と似ていますが、複数の継承されたプロトコルをカンマで区切ってリストするオプションがあります。
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}
Here’s an example of a protocol that inherits the TextRepresentable
protocol from above:
上記の TextRepresentable
プロトコルを継承するプロトコルの例を次に示します。
protocol PrettyTextRepresentable: TextRepresentable {
var prettyTextualDescription: String { get }
}
This example defines a new protocol, PrettyTextRepresentable
, which inherits from TextRepresentable
. Anything that adopts PrettyTextRepresentable
must satisfy all of the requirements enforced by TextRepresentable
, plus the additional requirements enforced by PrettyTextRepresentable
. In this example, PrettyTextRepresentable
adds a single requirement to provide a gettable property called prettyTextualDescription
that returns a String
.
この例では、TextRepresentable
を継承する新しいプロトコル PrettyTextRepresentable
を定義します。 PrettyTextRepresentable
を採用するものはすべて、TextRepresentable
によって強制されるすべての要件に加え、PrettyTextRepresentable
によって強制される追加の要件を満たさなければなりません。 この例では、PrettyTextRepresentable
は、String
を返す prettyTextualDescription
という取得可能なプロパティを提供するという 1 つの要件を追加します。
The SnakesAndLadders
class can be extended to adopt and conform to PrettyTextRepresentable
:
SnakesAndLadders
クラスは、PrettyTextRepresentable
を採用して準拠するように拡張できます。
extension SnakesAndLadders: PrettyTextRepresentable {
var prettyTextualDescription: String {
var output = textualDescription + ":\n"
for index in 1...finalSquare {
switch board[index] {
case let ladder where ladder > 0:
output += "▲ "
case let snake where snake < 0:
output += "▼ "
default:
output += "○ "
}
}
return output
}
}
This extension states that it adopts the PrettyTextRepresentable
protocol and provides an implementation of the prettyTextualDescription
property for the SnakesAndLadders
type. Anything that’s PrettyTextRepresentable
must also be TextRepresentable
, and so the implementation of prettyTextualDescription
starts by accessing the textualDescription
property from the TextRepresentable
protocol to begin an output string. It appends a colon and a line break, and uses this as the start of its pretty text representation. It then iterates through the array of board squares, and appends a geometric shape to represent the contents of each square:
この拡張機能は、PrettyTextRepresentable
プロトコルを採用し、SnakesAndLadders
型の prettyTextualDescription
プロパティの実装を提供することを示しています。 PrettyTextRepresentable
であるものはすべて TextRepresentable
である必要があるため、prettyTextualDescription
の実装は、TextRepresentable
プロトコルから textualDescription
プロパティにアクセスして出力文字列を開始することから始まります。 コロンと改行を追加し、これを可愛いテキスト表現の開始として使用します。 次に、ボードの正方形の配列を反復処理し、各正方形の内容を表す幾何学的形状を追加します。
- If the square’s value is greater than
0
, it’s the base of a ladder, and is represented by▲
. - 正方形の値が 0 より大きい場合、それははしごの基礎であり、▲ で表されます。
- If the square’s value is less than
0
, it’s the head of a snake, and is represented by▼
. - 四角形の値が 0 未満の場合、それは蛇の頭であり、▼ で表されます。
- Otherwise, the square’s value is
0
, and it’s a “free” square, represented by○
. - それ以外の場合、正方形の値は 0 であり、○ で表される「空き」正方形です。
The prettyTextualDescription
property can now be used to print a pretty text description of any SnakesAndLadders
instance:
prettyTextualDescription
プロパティを使用して、SnakesAndLadders
インスタンスのわかりやすいテキストの説明を出力できるようになりました。
print(game.prettyTextualDescription)
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
Class-Only Protocols
クラス専用プロトコル
You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject
protocol to a protocol’s inheritance list.
AnyObject
プロトコルをプロトコルの継承リストに追加することで、プロトコルの採用をクラス型(構造体や列挙型ではない)に制限できます。
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
In the example above, SomeClassOnlyProtocol
can only be adopted by class types. It’s a compile-time error to write a structure or enumeration definition that tries to adopt SomeClassOnlyProtocol
.
上の例では、SomeClassOnlyProtocol
はクラス 型でのみ採用できます。 SomeClassOnlyProtocol
を採用しようとする構造体または列挙定義を作成すると、コンパイル時エラーになります。
Note
注釈
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics. For more about reference and value semantics, see Structures and Enumerations Are Value Types and Classes Are Reference Types.
クラス専用プロトコルは、そのプロトコルの要件によって定義された動作が、適合する型が値セマンティクスではなく参照セマンティクスを持つことを前提または要求する場合に使用します。 参照セマンティクスと値セマンティクスの詳細については、「構造体と列挙型は値の型」と「クラスは参照型」を参照してください。
Protocol Composition
プロトコル構成
It can be useful to require a type to conform to multiple protocols at the same time. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions behave as if you defined a temporary local protocol that has the combined requirements of all protocols in the composition. Protocol compositions don’t define any new protocol types.
型が複数のプロトコルに同時に準拠することを要求すると便利な場合があります。 プロトコル構成を使用して、複数のプロトコルを 1 つの要件に組み合わせることができます。 プロトコル構成は、構成内のすべてのプロトコルの要件を組み合わせた一時的なローカル プロトコルを定義したかのように動作します。 プロトコル構成では、新しいプロトコル 型は定義されません。
Protocol compositions have the form SomeProtocol & AnotherProtocol
. You can list as many protocols as you need, separating them with ampersands (&
). In addition to its list of protocols, a protocol composition can also contain one class type, which you can use to specify a required superclass.
プロトコル構成には、SomeProtocol & AnotherProtocol
という形式があります。 アンパサンド (&
) で区切って、必要な数のプロトコルをリストできます。 プロトコルのリストに加えて、プロトコル構成には 1 つのクラス 型を含めることもでき、これを使用して必要なスーパークラスを指定できます。
Here’s an example that combines two protocols called Named
and Aged
into a single protocol composition requirement on a function parameter:
以下は、Named
と Aged
という 2 つのプロトコルを関数パラメータの単一のプロトコル構成要件に結合する例です。
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Prints "Happy birthday, Malcolm, you're 21!"
In this example, the Named
protocol has a single requirement for a gettable String
property called name
. The Aged
protocol has a single requirement for a gettable Int
property called age
. Both protocols are adopted by a structure called Person
.
この例では、Named
プロトコルには、name
という取得可能な String
プロパティに対する要件が 1 つあります。 Aged
プロトコルには、age
と呼ばれる取得可能な Int
プロパティに対する要件が 1 つあります。 どちらのプロトコルも person
と呼ばれる構造で採用されています。
The example also defines a wishHappyBirthday(to:)
function. The type of the celebrator
parameter is Named & Aged
, which means “any type that conforms to both the Named
and Aged
protocols.” It doesn’t matter which specific type is passed to the function, as long as it conforms to both of the required protocols.
この例では、wishHappyBirthday(to:)
関数も定義しています。 セレブレーター パラメータの型は Named & Aged
で、これは「Named
プロトコルと Aged
プロトコルの両方に準拠する任意の型」を意味します。 必要なプロトコルの両方に準拠している限り、どの特定の型が関数に渡されるかは関係ありません。
The example then creates a new Person
instance called birthdayPerson
and passes this new instance to the wishHappyBirthday(to:)
function. Because Person
conforms to both protocols, this call is valid, and the wishHappyBirthday(to:)
function can print its birthday greeting.
次に、この例では、birthdayperson
という新しい Person
インスタンスを作成し、この新しいインスタンスを wishHappyBirthday(to:)
関数に渡します。 Person
は両方のプロトコルに準拠しているため、この呼び出しは有効であり、wishHappyBirthday(to:)
関数は誕生日の挨拶を出力できます。
Here’s an example that combines the Named
protocol from the previous example with a Location
class:
以下は、前の例の Named
プロトコルと Location
クラスを組み合わせた例です。
class Location {
var latitude: Double
var longitude: Double
init(latitude: Double, longitude: Double) {
self.latitude = latitude
self.longitude = longitude
}
}
class City: Location, Named {
var name: String
init(name: String, latitude: Double, longitude: Double) {
self.name = name
super.init(latitude: latitude, longitude: longitude)
}
}
func beginConcert(in location: Location & Named) {
print("Hello, \(location.name)!")
}
let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)
beginConcert(in: seattle)
// Prints "Hello, Seattle!"
The beginConcert(in:)
function takes a parameter of type Location & Named
, which means “any type that’s a subclass of Location
and that conforms to the Named
protocol.” In this case, City
satisfies both requirements.
beginConcert(in:)
関数は、Location & Named
型のパラメータを受け取ります。これは、「Location
のサブクラスであり、Named
プロトコルに準拠する任意の型」を意味します。 この場合、City
は両方の要件を満たします。
Passing birthdayPerson
to the beginConcert(in:)
function is invalid because Person
isn’t a subclass of Location
. Likewise, if you made a subclass of Location
that didn’t conform to the Named
protocol, calling beginConcert(in:)
with an instance of that type is also invalid.
Person
は Location
のサブクラスではないため、birthdayperson
を beginConcert(in:)
関数に渡すことは無効です。 同様に、Named
プロトコルに準拠していない Location
のサブクラスを作成した場合、その型のインスタンスを使用して beginConcert(in:)
を呼び出すことも無効になります。
Checking for Protocol Conformance
プロトコルの適合性のチェック
You can use the is
and as
operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type:
「型キャスト」で説明されている is
演算子と as
演算子を使用して、プロトコルの適合性を確認し、特定のプロトコルにキャストできます。 プロトコルのチェックとプロトコルへのキャストは、型のチェックとキャストとまったく同じ構文に従います。
- The
is
operator returnstrue
if an instance conforms to a protocol and returnsfalse
if it doesn’t. is
演算子は、インスタンスがプロトコルに準拠している場合はtrue
を返し、準拠していない場合はfalse
を返します。- The
as?
version of the downcast operator returns an optional value of the protocol’s type, and this value isnil
if the instance doesn’t conform to that protocol. as?
ダウンキャスト演算子のバージョンはプロトコルの型のオプションの値を返します。インスタンスがそのプロトコルに準拠していない場合、この値はnil
になります。- The
as!
version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast doesn’t succeed. as!
ダウンキャスト オペレーターのバージョンは、プロトコル 型へのダウンキャストを強制し、ダウンキャストが成功しない場合はランタイム エラーをトリガーします。
This example defines a protocol called HasArea
, with a single property requirement of a gettable Double
property called area
:
この例では、HasArea
というプロトコルを定義し、area
という取得可能な Double
プロパティの単一プロパティ要件を指定します。
protocol HasArea {
var area: Double { get }
}
Here are two classes, Circle
and Country
, both of which conform to the HasArea
protocol:
以下に 2 つのクラス、Circle と Country があります。どちらも HasArea プロトコルに準拠しています。
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
}
The Circle
class implements the area
property requirement as a computed property, based on a stored radius
property. The Country
class implements the area
requirement directly as a stored property. Both classes correctly conform to the HasArea
protocol.
Circle クラスは、保存された半径プロパティに基づいて、エリア プロパティ要件を計算されたプロパティとして実装します。 Country クラスは、保存されたプロパティとして面積要件を直接実装します。 どちらのクラスも HasArea プロトコルに正しく準拠しています。
Here’s a class called Animal
, which doesn’t conform to the HasArea
protocol:
これは、HasArea プロトコルに準拠していない、Animal というクラスです。
class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}
The Circle
, Country
and Animal
classes don’t have a shared base class. Nonetheless, they’re all classes, and so instances of all three types can be used to initialize an array that stores values of type AnyObject
:
Circle、 Country、Animal クラスには、共有の基本クラスがありません。 それにもかかわらず、これらはすべてクラスであるため、3 つの型すべてのインスタンスを使用して、AnyObject 型の値を格納する配列を初期化できます。
let objects: [AnyObject] = [
Circle(radius: 2.0),
Country(area: 243_610),
Animal(legs: 4)
]
The objects
array is initialized with an array literal containing a Circle
instance with a radius of 2 units; a Country
instance initialized with the surface area of the United Kingdom in square kilometers; and an Animal
instance with four legs.
objects
配列は、半径 2 単位の Circle インスタンスを含む配列リテラルで初期化されます。 英国の表面積を平方キロメートル単位で初期化した国インスタンス。 そして4本の足を持つ動物の実例です。
The objects
array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea
protocol:
objects
配列を反復できるようになり、配列内の各オブジェクトが HasArea
プロトコルに準拠しているかどうかを確認できるようになります。
for object in objects {
if let objectWithArea = object as? HasArea {
print("Area is \(objectWithArea.area)")
} else {
print("Something that doesn't have an area")
}
}
// Area is 12.5663708
// Area is 243610.0
// Something that doesn't have an area
Whenever an object in the array conforms to the HasArea
protocol, the optional value returned by the as?
operator is unwrapped with optional binding into a constant called objectWithArea
. The objectWithArea
constant is known to be of type HasArea
, and so its area
property can be accessed and printed in a type-safe way.
配列内のオブジェクトが HasArea
プロトコルに準拠する場合、as?
によって返されるオプションの値が返されます。 演算子は、objectWithArea
という定数へのオプションのバインディングでラップ解除されます。 objectWithArea
定数は HasArea
型であることが知られているため、その area
プロパティは型セーフな方法でアクセスして出力できます。
Note that the underlying objects aren’t changed by the casting process. They continue to be a Circle
, a Country
and an Animal
. However, at the point that they’re stored in the objectWithArea
constant, they’re only known to be of type HasArea
, and so only their area
property can be accessed.
基礎となるオブジェクトはキャストプロセスによって変更されないことに注意してください。 彼らは引き続きCircle
、Country
、Animal
であり続けます。 ただし、objectWithArea
定数に保存されている時点では、HasArea
型であることだけがわかっているため、その area
プロパティのみにアクセスできます。
Optional Protocol Requirements
オプションのプロトコル要件
You can define optional requirements for protocols. These requirements don’t have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the optional
modifier as part of the protocol’s definition. Optional requirements are available so that you can write code that interoperates with Objective-C. Both the protocol and the optional requirement must be marked with the @objc
attribute. Note that @objc
protocols can be adopted only by classes, not by structures or enumerations.
プロトコルのオプションの要件を定義できます。 これらの要件は、プロトコルに準拠する型によって実装される必要はありません。 オプションの要件には、プロトコル定義の一部としてoptional
の修飾子が接頭辞として付けられます。 Objective-C と相互運用するコードを作成できるように、オプションの要件を利用できます。 プロトコルとオプションの要件の両方に @objc
属性を付ける必要があります。 @objc
プロトコルはクラスでのみ採用でき、構造体や列挙では採用できないことに注意してください。
When you use a method or property in an optional requirement, its type automatically becomes an optional. For example, a method of type (Int) -> String
becomes ((Int) -> String)?
. Note that the entire function type is wrapped in the optional, not the method’s return value.
オプションの要件でメソッドまたはプロパティを使用すると、その型は自動的にオプションになります。 たとえば、(Int) -> String
型のメソッドは ((Int) -> String)?
になります。 メソッドの戻り値ではなく、関数型全体がオプションでラップされることに注意してください。
An optional protocol requirement can be called with optional chaining, to account for the possibility that the requirement was not implemented by a type that conforms to the protocol. You check for an implementation of an optional method by writing a question mark after the name of the method when it’s called, such as someOptionalMethod?(someArgument)
. For information on optional chaining, see Optional Chaining.
オプションのプロトコル要件は、その要件がプロトコルに準拠する型によって実装されていない可能性を考慮して、オプションのチェーンを使用して呼び出すことができます。 オプションのメソッドの実装を確認するには、someOptionalMethod?(someArgument)
のように、メソッドの呼び出し時にメソッド名の後に疑問符を書きます。 オプションのチェーンの詳細については、「オプションのチェーン」を参照してください。
The following example defines an integer-counting class called Counter
, which uses an external data source to provide its increment amount. This data source is defined by the CounterDataSource
protocol, which has two optional requirements:
次の例では、外部データ ソースを使用して増分量を提供する、Counter
という整数カウント クラスを定義します。 このデータ ソースは、CounterDataSource
プロトコルによって定義されており、次の 2 つのオプション要件があります。
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
The CounterDataSource
protocol defines an optional method requirement called increment(forCount:)
and an optional property requirement called fixedIncrement
. These requirements define two different ways for data sources to provide an appropriate increment amount for a Counter
instance.
CounterDataSource
プロトコルは、increment(forCount:)
と呼ばれるオプションのメソッド要件と、fixedIncrement
と呼ばれるオプションのプロパティ要件を定義します。 これらの要件は、データソースがCounter
インスタンスに適切な増分量を提供するための 2 つの異なる方法を定義します。
Note
注釈
Strictly speaking, you can write a custom class that conforms to CounterDataSource
without implementing either protocol requirement. They’re both optional, after all. Although technically allowed, this wouldn’t make for a very good data source.
厳密に言えば、どちらのプロトコル要件も実装しなくても、CounterDataSource に準拠するカスタム クラスを作成できます。 結局のところ、どちらもオプションです。 技術的には許可されていますが、これはあまり優れたデータ ソースとは言えません。
The Counter
class, defined below, has an optional dataSource
property of type CounterDataSource?
:
以下で定義されている Counter
クラスには、CounterDataSource
? 型のオプションの dataSource
プロパティがあります。
class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.increment?(forCount: count) {
count += amount
} else if let amount = dataSource?.fixedIncrement {
count += amount
}
}
}
The Counter
class stores its current value in a variable property called count
. The Counter
class also defines a method called increment
, which increments the count
property every time the method is called.
Counter
クラスは、count
と呼ばれる変数プロパティに現在の値を保存します。 Counter
クラスは、increment
と呼ばれるメソッドも定義します。このメソッドは、メソッドが呼び出されるたびに count
プロパティをインクリメントします。
The increment()
method first tries to retrieve an increment amount by looking for an implementation of the increment(forCount:)
method on its data source. The increment()
method uses optional chaining to try to call increment(forCount:)
, and passes the current count
value as the method’s single argument.
increment()
メソッドは、まず、データ ソース上で increment(forCount:)
メソッドの実装を検索することにより、増分量を取得しようとします。 increment()
メソッドは、オプションのチェーンを使用して increment(forCount:)
の呼び出しを試み、現在のcount
値をメソッドの 1 つの引数として渡します。
Note that two levels of optional chaining are at play here. First, it’s possible that dataSource
may be nil
, and so dataSource
has a question mark after its name to indicate that increment(forCount:)
should be called only if dataSource
isn’t nil
. Second, even if dataSource
does exist, there’s no guarantee that it implements increment(forCount:)
, because it’s an optional requirement. Here, the possibility that increment(forCount:)
might not be implemented is also handled by optional chaining. The call to increment(forCount:)
happens only if increment(forCount:)
exists — that is, if it isn’t nil
. This is why increment(forCount:)
is also written with a question mark after its name.
ここでは 2 つのレベルのオプションの連鎖が機能していることに注意してください。 まず、dataSource
が nil
である可能性があるため、dataSource
には、dataSource
が nil
でない場合にのみ increment(forCount:)
を呼び出す必要があることを示すために、名前の後に疑問符が付いています。 次に、dataSource
が存在する場合でも、increment(forCount:)
はオプションの要件であるため、それが実装されるという保証はありません。 ここで、increment(forCount:)
が実装されない可能性も、オプションのチェーンによって処理されます。 increment(forCount:)
の呼び出しは、increment(forCount:)
が存在する場合、つまり nil
でない場合にのみ発生します。 これが、increment(forCount:)
の名前の後に疑問符が付いている理由です。
Because the call to increment(forCount:)
can fail for either of these two reasons, the call returns an optional Int
value. This is true even though increment(forCount:)
is defined as returning a non-optional Int
value in the definition of CounterDataSource
. Even though there are two optional chaining operations, one after another, the result is still wrapped in a single optional. For more information about using multiple optional chaining operations, see Linking Multiple Levels of Chaining.
increment(forCount:)
の呼び出しはこれら 2 つの理由のいずれかで失敗する可能性があるため、この呼び出しはオプションの Int
値を返します。 これは、CounterDataSource
の定義で increment(forCount:)
がオプションではない Int
値を返すように定義されている場合でも当てはまります。 2 つのオプションの連鎖操作が次々にある場合でも、結果は 1 つのオプションにラップされます。 複数のオプションのチェーン操作の使用の詳細については、「複数レベルのチェーンのリンク」を参照してください。
After calling increment(forCount:)
, the optional Int
that it returns is unwrapped into a constant called amount
, using optional binding. If the optional Int
does contain a value — that is, if the delegate and method both exist, and the method returned a value — the unwrapped amount
is added onto the stored count
property, and incrementation is complete.
increment(forCount:)
を呼び出した後、返されるオプションの Int
は、オプションのバインディングを使用して、amount
と呼ばれる定数にアンラップされます。 オプションの Int
に値が含まれている場合、つまり、デリゲートとメソッドの両方が存在し、メソッドが値を返した場合、ラップされていないamount
が格納されたcount
プロパティに追加され、増分が完了します。
If it’s not possible to retrieve a value from the increment(forCount:)
method — either because dataSource
is nil, or because the data source doesn’t implement increment(forCount:)
— then the increment()
method tries to retrieve a value from the data source’s fixedIncrement
property instead. The fixedIncrement
property is also an optional requirement, so its value is an optional Int
value, even though fixedIncrement
is defined as a non-optional Int
property as part of the CounterDataSource
protocol definition.
dataSource
が nil
であるか、データ ソースが increment(forCount:)
を実装していないため、increment(forCount:)
メソッドから値を取得できない場合、increment()
メソッドは値を取得しようとします。 代わりにデータ ソースの fixedIncrement
プロパティを使用します。 fixedIncrement
プロパティもオプションの要件であるため、fixedIncrement
が CounterDataSource
プロトコル定義の一部として非オプションの Int
プロパティとして定義されている場合でも、その値はオプションの Int
値になります。
Here’s a simple CounterDataSource
implementation where the data source returns a constant value of 3
every time it’s queried. It does this by implementing the optional fixedIncrement
property requirement:
ここでは、データ ソースがクエリされるたびに定数値 3
を返す単純な CounterDataSource
実装を示します。 これは、オプションの fixedIncrement
プロパティ要件を実装することで実現されます。
class ThreeSource: NSObject, CounterDataSource {
let fixedIncrement = 3
}
You can use an instance of ThreeSource
as the data source for a new Counter
instance:
ThreeSource
のインスタンスを新しい Counter
インスタンスのデータ ソースとして使用できます。
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
counter.increment()
print(counter.count)
}
// 3
// 6
// 9
// 12
The code above creates a new Counter
instance; sets its data source to be a new ThreeSource
instance; and calls the counter’s increment()
method four times. As expected, the counter’s count
property increases by three each time increment()
is called.
上記のコードは、新しい Counter
インスタンスを作成します。 データ ソースを新しい ThreeSource
インスタンスに設定します。 そしてカウンタの increment()
メソッドを 4 回呼び出します。 予想どおり、increment()
が呼び出されるたびに、カウンタの count
プロパティは 3 ずつ増加します。
Here’s a more complex data source called TowardsZeroSource
, which makes a Counter
instance count up or down towards zero from its current count
value:
ここでは、TowardsZeroSource
と呼ばれるより複雑なデータ ソースを示します。これは、Counter
インスタンスを現在のcount
値からゼロに向かってカウントアップまたはカウントダウンします。
class TowardsZeroSource: NSObject, CounterDataSource {
func increment(forCount count: Int) -> Int {
if count == 0 {
return 0
} else if count < 0 {
return 1
} else {
return -1
}
}
}
The TowardsZeroSource
class implements the optional increment(forCount:)
method from the CounterDataSource
protocol and uses the count
argument value to work out which direction to count in. If count
is already zero, the method returns 0
to indicate that no further counting should take place.
TowardsZeroSource
クラスは、CounterDataSource
プロトコルのオプションの increment(forCount:)
メソッドを実装し、count
引数の値を使用して、どの方向にカウントするかを決定します。count
がすでにゼロの場合、メソッドは 0
を返し、これ以上カウントを行わないことを示します。 。
You can use an instance of TowardsZeroSource
with the existing Counter
instance to count from -4
to zero. Once the counter reaches zero, no more counting takes place:
TowardsZeroSource
のインスタンスと既存の Counter
インスタンスを使用して、-4
から
ゼロまでカウントできます。 カウンタがゼロに達すると、それ以上のカウントは行われません。
counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
counter.increment()
print(counter.count)
}
// -3
// -2
// -1
// 0
// 0
Protocol Extensions
プロトコル拡張
Protocols can be extended to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.
プロトコルを拡張して、メソッド、イニシャライザ、サブスクリプト、および計算されたプロパティの実装を準拠する型に提供できます。 これにより、各型の個別の適合性やグローバル関数ではなく、プロトコル自体の動作を定義できるようになります。
For example, the RandomNumberGenerator
protocol can be extended to provide a randomBool()
method, which uses the result of the required random()
method to return a random Bool
value:
たとえば、RandomNumberGenerator
プロトコルを拡張して、必要な Random()
メソッドの結果を使用してランダムな Bool
値を返す RandomBool()
メソッドを提供できます。
extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}
By creating an extension on the protocol, all conforming types automatically gain this method implementation without any additional modification.
プロトコルに拡張機能を作成すると、追加の変更を加えることなく、準拠するすべての型がこのメソッド実装を自動的に取得します。
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Prints "Here's a random number: 0.3746499199817101"
print("And here's a random Boolean: \(generator.randomBool())")
// Prints "And here's a random Boolean: true"
Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol. Protocol inheritance is always specified in the protocol declaration itself.
プロトコル拡張では、準拠する型に実装を追加できますが、プロトコルを拡張したり、別のプロトコルから継承したりすることはできません。 プロトコルの継承は、常にプロトコル宣言自体で指定されます。
Providing Default Implementations
デフォルト実装の提供
You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.
プロトコル拡張を使用すると、そのプロトコルのメソッドまたは計算されたプロパティ要件にデフォルトの実装を提供できます。 準拠する型が必要なメソッドまたはプロパティの独自の実装を提供する場合、拡張機能によって提供される実装の代わりにその実装が使用されます。
Note
注釈
Protocol requirements with default implementations provided by extensions are distinct from optional protocol requirements. Although conforming types don’t have to provide their own implementation of either, requirements with default implementations can be called without optional chaining.
拡張機能によって提供されるデフォルト実装のプロトコル要件は、オプションのプロトコル要件とは異なります。 準拠する型はどちらの独自の実装も提供する必要はありませんが、デフォルトの実装を持つ要件はオプションのチェーンなしで呼び出すことができます。
For example, the PrettyTextRepresentable
protocol, which inherits the TextRepresentable
protocol can provide a default implementation of its required prettyTextualDescription
property to simply return the result of accessing the textualDescription
property:
たとえば、TextRepresentable
プロトコルを継承する PrettyTextRepresentable
プロトコルは、必要な prettyTextualDescription
プロパティのデフォルト実装を提供して、単に textualDescription
プロパティにアクセスした結果を返すことができます。
extension PrettyTextRepresentable {
var prettyTextualDescription: String {
return textualDescription
}
}
Adding Constraints to Protocol Extensions
プロトコル拡張への制約の追加
When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending by writing a generic where
clause. For more about generic where
clauses, see Generic Where Clauses.
プロトコル拡張を定義するときは、拡張のメソッドとプロパティが使用可能になる前に、準拠する型が満たさなければならない制約を指定できます。 これらの制約は、拡張するプロトコル名の後に一般的な where
句を記述して記述します。 一般的な where
句の詳細については、「汎用 Where 句」を参照してください。
For example, you can define an extension to the Collection
protocol that applies to any collection whose elements conform to the Equatable
protocol. By constraining a collection’s elements to the Equatable
protocol, a part of the Swift standard library, you can use the ==
and !=
operators to check for equality and inequality between two elements.
たとえば、要素が Equatable
プロトコルに準拠するCollection
に適用する、Collection
プロトコルの拡張機能を定義できます。 コレクションの要素を Swift 標準ライブラリの一部である Equatable
プロトコルに制限することで、==
演算子と !=
演算子を使用して 2 つの要素間の等価性と不平等性をチェックできます。
extension Collection where Element: Equatable {
func allEqual() -> Bool {
for element in self {
if element != self.first {
return false
}
}
return true
}
}
The allEqual()
method returns true
only if all the elements in the collection are equal.
allEqual()
メソッドは、コレクション内のすべての要素が等しい場合にのみ true
を返します。
Consider two arrays of integers, one where all the elements are the same, and one where they aren’t:
2 つの整数の配列を考えてみましょう。1 つはすべての要素が同じで、もう 1 つはすべての要素が同じではありません。
let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]
Because arrays conform to Collection
and integers conform to Equatable
, equalNumbers
and differentNumbers
can use the allEqual()
method:
配列は Collection
に準拠し、整数は Equatable
に準拠するため、equalNumbers
と DifferentNumbers
は allEqual()
メソッドを使用できます。
print(equalNumbers.allEqual())
// Prints "true"
print(differentNumbers.allEqual())
// Prints "false"
Note
注釈
If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift uses the implementation corresponding to the most specialized constraints.
適合する型が、同じメソッドまたはプロパティの実装を提供する複数の制約付き拡張機能の要件を満たしている場合、Swift は最も特殊な制約に対応する実装を使用します。