Protocols¶ プロトコル¶
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(クラス定義が、ここにきます)
- }
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: ただ1つのインスタンスプロパティ要件を持つプロトコルの例が、ここにあります:
- 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
型はfullName
と呼ばれる、String
型である、取得可能なインスタンスプロパティを持たなければならないことを述べます。
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"(john.fullNameは、「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
と呼ばれる1つの格納プロパティを持ちます、それは、型String
です。これは、FullyNamed
プロトコルの唯一の要件に適合します、したがってそのPerson
が正しくそのプロトコルに従ったことを意味します。(プロトコル要件が満たされないならば、スウィフトは実行時にエラーを報告します)。
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"(ncc1701.fullNameは、USSエンタープライズです)
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: 以下の例は、1つのインスタンスメソッド要件で、プロトコルを定義します:
- 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
は、あらゆる準拠型にrandom
と呼ばれるインスタンスメソッドを持つことを要求します、それは、それが呼ばれた時はいつでもあるDouble
値を返すものです。それはプロトコルの一部として指定されないけれども、この値は0.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"(「ここに任意の数: 0.3746499199817101があります」を出力します)
- print("And another one: \(generator.random())")
- // Prints "And another one: 0.729023776863283"(「さらにもう1つ: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.
メソッドがそれが属しているインスタンスを修正する(または変化させる)ことは、時々必要です。値型(すなわち、構造体と列挙)のインスタンスメソッドのために、あなたはmutating
キーワードをメソッドのfunc
キーワードの前に置いて、メソッドがそれが属しているインスタンスおよびそのインスタンスのあらゆるプロパティを修正するのを許可されることを示します。この過程は、値型をインスタンスメソッド内から修正するで記述されます。
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.
下の例は、Togglable
と呼ばれるプロトコルを定義します、それは、toggle
と呼ばれる1つのインスタンスメソッド要件を定義します。その名前が暗示するように、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
プロトコルをある構造体または列挙のために実装するならば、その構造体または列挙は、同様にmutating
として印される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(lightSwitchは、現在.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(SomeProtocol準拠からの「required」;SomeSuperClasからの「override」)
- required override init() {
- // initializer implementation goes here(イニシャライザ実装がここに来ます)
- }
- }
Failable Initializer Requirements¶ 失敗できるイニシャライザ要件¶
Protocols can define failable initializer requirements for conforming types, as defined in Failable Initializers. プロトコルは、失敗できるイニシャライザで記述されるように、準拠している型に対して失敗できるイニシャライザ要件を定義することができます。
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. Nonetheless, you can use protocols as a fully fledged types in your code. Using a protocol as a type is sometimes called an existential type, which comes from the phrase “there exists a type T such that T conforms to the protocol”. プロトコルは、実際に少しの機能性も実装しません。それにもかかわらず、あなたはプロトコルを完全に一人前の型としてあなたのコードにおいて使用できます。プロトコルを型として使うことは、ときどき存在型と呼ばれます、それは語句 “そこに型Tが存在する、そのようなTはそのプロトコルに準拠する” から来ています。
You can use a protocol in many places where other types are allowed, including: あなたは、プロトコルを、他の型が許可される多くの場所で使用できます、以下を含みます:
- As a parameter type or return type in a function, method, or initializer 関数、メソッド、またはイニシャライザにおいてパラメータ型または戻り型として
- As the type of a constant, variable, or property 定数、変数、またはプロパティの型として
- As the type of items in an array, dictionary, or other container 配列、辞書、または他のコンテナ中の項目の型として
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
).
プロトコルが型であるので、それらの名前を大文字で開始してください(例えばFullyNamed
とRandomNumberGenerator
のように)、それによってスウィフトでの他の型の名前(例えばInt
、String
、およびDouble
)と釣り合いがとれます。
Here’s an example of a protocol used as a type: 型として使われるプロトコルの例は、ここにあります:
- class Dice {
- let sides: Int
- let generator: RandomNumberGenerator
- init(sides: Int, generator: RandomNumberGenerator) {
- self.sides = sides
- self.generator = generator
- }
- func roll() -> Int {
- return Int(generator.random() * Double(sides)) + 1
- }
- }
This example defines a new class called Dice
, which represents an n-sided dice for use in a board game. Dice
instances have an integer property called sides
, which represents how many sides they have, and a property called generator
, which provides a random number generator from which to create dice roll values.
この例はDice
と呼ばれる新しいクラスを定義します、それは、ボードゲームで使うのためにn面のさいころを表します。Dice
インスタンスは、それがどれくらいの面を持つのかを表すsides
と呼ばれる整数プロパティ、そしてそこからさいころを振った値を作成する乱数生成器を提供するgenerator
と呼ばれるプロパティを持ちます。
The generator
property is of type RandomNumberGenerator
. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator
protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator
protocol. Because its type is RandomNumberGenerator
, code inside the Dice
class can only interact with generator
in ways that apply to all generators that conform to this protocol. That means it can’t use any methods or properties that are defined by the underlying type of the generator. However, you can downcast from a protocol type to an underlying type in the same way you can downcast from a superclass to a subclass, as discussed in Downcasting.
generator
プロパティは、型RandomNumberGenerator
のものです。したがって、あなたはそれをRandomNumberGenerator
プロトコルを採用するあらゆる型のインスタンスに設定できます。そのインスタンスがRandomNumberGenerator
プロトコルを採用しなければならないことをのぞいては、あなたがこのプロパティに代入するところのインスタンスに必要とされるものは他に何もありません。それの型がRandomNumberGenerator
であることから、Dice
クラスの内部のコードは、全ての生成子にこのプロトコルに準拠することを適用するという方法でgenerator
と相互作用できるだけです。それは意味するのは、それが生成子の基礎をなす型によって定義されるどんなメソッドまたはプロパティも使用できないということです。しかしながら、あなたはあるプロトコル型からある基礎をなす型へとダウンキャストすることが、あなたがスーパークラスからサブクラスへとダウンキャスト出来るのと同じ方法で可能です、ダウンキャストで記述されるように。
Dice
also has an initializer, to set up its initial state. This initializer has a parameter called generator
, which is also of type RandomNumberGenerator
. You can pass a value of any conforming type in to this parameter when initializing a new Dice
instance.
Dice
はまた、その最初の状態を設定するために、イニシャライザを持ちます。このイニシャライザは、generator
と呼ばれるパラメータを持ちます、それもまた、型RandomNumberGenerator
です。新しいDice
インスタンスを初期化するとき、あなたはどんな準拠型の値でもこのパラメータに渡すことができます。
Dice
provides one instance method, roll
, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random()
method to create a new random number between 0.0
and 1.0
, and uses this random number to create a dice roll value within the correct range. Because generator
is known to adopt RandomNumberGenerator
, it’s guaranteed to have a random()
method to call.
Dice
は1つのインスタンスメソッド、roll
を提供します、それは、1とさいころ上の面の数との間の整数値を返します。このメソッドは、0.0
と1.0
の間で新しい乱数をつくるgeneratorのrandom()
メソッドを呼んで、この乱数を正しい範囲内でさいころを振った値をつくるために使います。generator
がRandomNumberGenerator
を採用すると知られているので、それはrandom()
メソッドを呼ぶことを保証されます。
Here’s how the Dice
class can be used to create a six-sided dice with a LinearCongruentialGenerator
instance as its random number generator:
Dice
クラスが、6面のさいころをつくるためにその乱数生成器としてLinearCongruentialGenerator
インスタンスをつかってどのように使われることができるかが、ここにあります:
- var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
- for _ in 1...5 {
- print("Random dice roll is \(d6.roll())")
- }
- // Random dice roll is 3(無作為にさいころを転がして、3です)
- // Random dice roll is 5(無作為にさいころを転がして、5です)
- // Random dice roll is 4(無作為にさいころを転がして、4です)
- // Random dice roll is 5(無作為にさいころを転がして、5です)
- // Random dice roll is 4(無作為にさいころを転がして、4です)
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 two protocols for use with dice-based board games: 下の例は、さいころに基づく様々なボードゲームで使うために、2つのプロトコルを定義します:
- protocol DiceGame {
- var dice: Dice { get }
- func play()
- }
- protocol DiceGameDelegate: AnyObject {
- func gameDidStart(_ game: DiceGame)
- func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
- func gameDidEnd(_ game: DiceGame)
- }
The DiceGame
protocol is a protocol that can be adopted by any game that involves dice.
DiceGame
プロトコルは、さいころが関わるどんなゲームによってでも採用されることができるプロトコルです。
The DiceGameDelegate
protocol can be adopted to track the progress of a 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 SnakesAndLadders
class later in this chapter 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.
DiceGameDelegate
プロトコルが採用されることで、DiceGame
の進捗を追いかけることができます。強い参照循環を防ぐために、委任先は弱い参照として宣言されます。弱い参照についての詳細は、クラスインスタンス間の強い参照循環を見てください。プロトコルをクラス専用とすることは、SnakesAndLadders
クラスに後でこの章においてその委任先が弱い参照を使わなければならないことを宣言させます。クラス専用プロトコルは、AnyObject
からのそれの継承によって印されます、クラス専用プロトコルにおいて議論されるように。
Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice
instance for its dice-rolls; to adopt the DiceGame
protocol; and to notify a DiceGameDelegate
about its progress:
制御の流れで元々は紹介されるヘビとはしごゲームのひとつの改作が、ここにあります。この版は改変され、それにより、それのさいころ振りにDice
インスタンスを使用します;DiceGame
プロトコルを採用します;そして、その進歩についてDiceGameDelegate
に通知します:
- class SnakesAndLadders: DiceGame {
- let finalSquare = 25
- let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
- var square = 0
- var board: [Int]
- init() {
- board = Array(repeating: 0, count: finalSquare + 1)
- board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
- board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
- }
- weak var delegate: DiceGameDelegate?
- func play() {
- square = 0
- delegate?.gameDidStart(self)
- gameLoop: while square != finalSquare {
- let diceRoll = dice.roll()
- delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
- switch square + diceRoll {
- case finalSquare:
- break gameLoop
- case let newSquare where newSquare > finalSquare:
- continue gameLoop
- default:
- square += diceRoll
- square += board[square]
- }
- }
- delegate?.gameDidEnd(self)
- }
- }
For a description of the Snakes and Ladders gameplay, see Break. ヘビとはしごのゲームプレイの解説として、Breakを見てください。
This version of the game is wrapped up as a class called SnakesAndLadders
, which adopts the DiceGame
protocol. It provides a gettable dice
property and a play()
method in order to conform to the protocol. (The dice
property is declared as a constant property because it doesn’t need to change after initialization, and the protocol only requires that it must be gettable.)
ゲームのこの改作は、SnakesAndLadders
と呼ばれるクラスで包まれます、それは、DiceGame
プロトコルを採用します。それは、プロトコルに従うために取得可能なdice
プロパティとplay()
メソッドを提供します。(dice
プロパティは定数プロパティとして宣言されます、なぜなら、それが初期化の後に変化する必要がなく、そして、プロトコルはそれが取得可能なことを必要とするだけであるからです)。
The Snakes and Ladders game board setup takes place within the class’s init()
initializer. All game logic is moved into the protocol’s play
method, which uses the protocol’s required dice
property to provide its dice roll values.
ヘビとはしごゲーム盤設定は、このクラスのinit()
イニシャライザ内で行われます。全てのゲーム論理は、プロトコルのplay
メソッドに引っ越します、それは、プロトコルの要求するdice
プロパティを使ってそれのさいころ振りの値を提供します。
Note that the delegate
property is defined as an optional DiceGameDelegate
, because a delegate isn’t required in order to play the game. Because it’s of an optional type, the delegate
property is automatically set to an initial value of nil
. Thereafter, the game instantiator has the option to set the property to a suitable delegate. Because the DiceGameDelegate
protocol is class-only, you can declare the delegate to be weak
to prevent reference cycles.
delegate
プロパティが、オプショナルのDiceGameDelegate
として定義される点に注意してください、delegateがゲームをプレイするために必須でないからです。それがオプショナル型であるので、delegate
プロパティは自動的に初期値のnilに
設定されます。その後は、このゲームのイニシャライザは、このプロパティを適当な委任先に設定する選択肢を持ちます。DiceGameDelegate
プロトコルがクラス専用であることから、あなたは委任先をweak
であると宣言して参照循環を防ぐことができます。
DiceGameDelegate
provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play()
method above, and are called when a new game starts, a new turn begins, or the game ends.
DiceGameDelegate
は、3つのメソッドをゲームの進捗を追うために提供します。これらの3つのメソッドは、上のplay()
メソッド内のゲーム論理に組み込まれています、そして、新しいゲームが始まるとき、新しいターンを開始するとき、あるいはこのゲームが終わるとき、呼ばれます。
Because the delegate
property is an optional DiceGameDelegate
, the play()
method uses optional chaining each time it calls a method on the delegate. If the delegate
property is nil, these delegate calls fail gracefully and without error. If the delegate
property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders
instance as a parameter.
delegate
プロパティがオプショナルのDiceGameDelegate
であるので、play()
メソッドは、それが委任先でメソッドを呼ぶたびにオプショナル連鎖を使います。delegate
プロパティがnilならば、これらの委任先呼び出しはエラーなしで美しく失敗します。delegate
プロパティがnilでないならば、委任先のさまざまなメソッドが呼ばれます、そしてパラメータとしてSnakesAndLadders
インスタンスを渡されます。
This next example shows a class called DiceGameTracker
, which adopts the DiceGameDelegate
protocol:
この次の例はDiceGameTracker
と呼ばれるクラスを示します、それは、DiceGameDelegate
プロトコルを採用します:
- class DiceGameTracker: DiceGameDelegate {
- var numberOfTurns = 0
- func gameDidStart(_ game: DiceGame) {
- numberOfTurns = 0
- if game is SnakesAndLadders {
- print("Started a new game of Snakes and Ladders")
- }
- print("The game is using a \(game.dice.sides)-sided dice")
- }
- func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
- numberOfTurns += 1
- print("Rolled a \(diceRoll)")
- }
- func gameDidEnd(_ game: DiceGame) {
- print("The game lasted for \(numberOfTurns) turns")
- }
- }
DiceGameTracker
implements all three methods required by DiceGameDelegate
. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns
property to zero when the game starts, increments it each time a new turn begins, and prints out the total number of turns once the game has ended.
DiceGameTracker
は、DiceGameDelegate
によって要求される3つのメソッド全てを実装します。それは、あるゲームがとったターンの数の情報を得続けるためにこれらのメソッドを使用します。それは、ゲームが始まるときnumberOfTurns
プロパティをゼロに再設定します、新しいターンが開始するときそれぞれそれを増加させます、そしてひとたびゲームが終わってしまったならばターンの総数を出力します。
The implementation of gameDidStart(_:)
shown above uses the game
parameter to print some introductory information about the game that’s about to be played. The game
parameter has a type of DiceGame
, not SnakesAndLadders
, and so gameDidStart(_:)
can access and use only methods and properties that are implemented as part of the DiceGame
protocol. However, the method is still able to use type casting to query the type of the underlying instance. In this example, it checks whether game
is actually an instance of SnakesAndLadders
behind the scenes, and prints an appropriate message if so.
上で示されるgameDidStart(_:)
の実装は、game
パラメータを使って、プレイされようとしているゲームに関する若干の紹介の情報を出力します。game
パラメータは、型DiceGame
を持ちます、SnakesAndLadders
ではありません、なので、gameDidStart(_:)
はDiceGame
プロトコルの一部として実施されるメソッドとプロパティだけにアクセスして使用することができます。しかし、このメソッドは依然として基盤インスタンスの型についてたずねるために型キャストを使うことができます。この例では、game
が実際に舞台裏でSnakesAndLadders
のインスタンスであるかどうか調べて、もしそうならば適切なメッセージを出力します。
The gameDidStart(_:)
method also accesses the dice
property of the passed game
parameter. Because game
is known to conform to the DiceGame
protocol, it’s guaranteed to have a dice
property, and so the gameDidStart(_:)
method is able to access and print the dice’s sides
property, regardless of what kind of game is being played.
gameDidStart(_:)
メソッドはまた、渡されたgame
パラメータのdice
プロパティにアクセスします。game
がDiceGame
プロトコルに従うと知られているので、それはdice
プロパティを持つと保証されます、なので、gameDidStart(_:)
メソッドは、どんな種類のゲームがプレイされているかに関係なく、diceのsides
プロパティにアクセスして出力することができます。
Here’s how DiceGameTracker
looks in action:
動作中のDiceGameTracker
がどのように見えるかは、ここにあります:
- let tracker = DiceGameTracker()
- let game = SnakesAndLadders()
- game.delegate = tracker
- game.play()
- // Started a new game of Snakes and Ladders(ヘビとはしごの新しいゲームを始める)
- // The game is using a 6-sided dice(ゲームは、6面のさいころを使っています)
- // Rolled a 3(3を出した)
- // Rolled a 5(5を出した)
- // Rolled a 4(4を出した)
- // Rolled a 5(5を出した)
- // The game lasted for 4 turns(ゲームは、4回続きました)
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"(「ひとつの12面さいころ」を出力します)
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"(「25ますのヘビとはしごのゲーム」を出力します)
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:
TextRepresentable
が必要な型であるどこででも、Hamster
のインスタンスが現在使われることができます:
- 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.
スウィフトは、自動的にプロトコル準拠をEquatable
、Hashable
、そしてComparable
に対して提供することが多くの単純な場合において可能です。この合成実装を使うことは、あなたが繰り返しの常用文コードを書いてプロトコル要件をあなた自身で実装する必要はないのを意味します。
Swift provides a synthesized implementation of Equatable
for the following kinds of custom types:
スウィフトは、Equatable
の合成実装を以下の種類のあつらえの型に提供します:
- Structures that have only stored properties that conform to the
Equatable
protocolEquatable
プロトコルに準拠する格納プロパティだけを持つ構造体 - Enumerations that have only associated types that conform to the
Equatable
protocolEquatable
プロトコルに準拠する関連型だけを持つ列挙 - 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.
下の例は、Vector3D
構造体を3次元の位置ベクトル(x, y, z)
に対して定義する、Vector2D
構造体に似たものです。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."(「これらの2つのベクトルはまた等しいです。」を出力します)
Swift provides a synthesized implementation of Hashable
for the following kinds of custom types:
スウィフトは、Hashable
の合成実装を以下の種類のあつらえの型に提供します:
- Structures that have only stored properties that conform to the
Hashable
protocolHashable
プロトコルに準拠する格納プロパティだけを持つ構造体 - Enumerations that have only associated types that conform to the
Hashable
protocolHashable
プロトコルに準拠する関連型だけを持つ列挙 - 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:)
の合成実装を受け取るには、Hashable
への準拠を本来の宣言を含むファイルにおいて宣言してください、hash(into:)
メソッドをあなた自身で実装することなしに。
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.
スウィフトは、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
列挙を、初心者(beginners)、中級者(intermediates)、そして熟練者(experts)に対する事例(ケース節)で定義します。expertsは加えて、彼らが持つ星の数によってランク付けされます。
- 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(25ますのヘビとはしごのゲーム)
- // A 12-sided dice(ひとつの12面のさいころ遊び)
- // 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
ではありません、たとえ舞台裏の実際のインスタンスがそれらの型のうちの1つであるとしてもです。それでもなお、それが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
.
この例は、ある新しいプロトコル、PrettyTextRepresentable
を定義します、それは、TextRepresentable
から継承を受けます。PrettyTextRepresentable
を採用するどんなものでも、TextRepresentable
によって強制される要件の全て、それに加えてPrettyTextRepresentable
によって強制される追加の要件を満たさなければなりません。この例では、PrettyTextRepresentable
は1つの要件を加えて、String
を返すprettyTextualDescription
と呼ばれる取得可能なプロパティを提供するようにします。
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
プロトコルを採用してprettyTextualDescription
プロパティの実装をSnakesAndLadders
型に提供することです。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:(25ますのヘビとはしごのゲーム:)
- // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
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つのプロトコルを1つのプロトコル合成要件に結合する例があります:
- 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!"(「誕生日おめでとうマルコム、あなたは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
プロトコルは、取得可能なString
プロパティでname
と呼ばれるものに対するただ1つの要件を持ちます。Aged
プロトコルは、取得可能なInt
プロパティでage
と呼ばれるものに対するただ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:)
関数を定義します。celebrator
パラメータの型は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:
ここに1つの例があります、それは前の例からの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
のパラメータを1つとります、それは「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.
birthdayPerson
をbeginConcert(in:)
関数に渡すことは無効です、なぜならPerson
はLocation
のサブクラスではないからです。同様に、あなたがLocation
のサブクラスでNamed
プロトコルに準拠しないものを作成したならば、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
:
この例は、area
と呼ばれる取得可能なDouble
プロパティである1つだけのプロパティ要件をもつ、HasArea
と呼ばれるプロトコルを定義します:
- protocol HasArea {
- var area: Double { get }
- }
Here are two classes, Circle
and Country
, both of which conform to the HasArea
protocol:
その両方ともHasArea
プロトコルに従う2つのクラス、Circle
とCountry
が、ここにあります:
- 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
クラスはarea
プロパティ要件を、格納radius
プロパティに基づいて計算プロパティとして、満たします。Country
クラスは、area
要件を格納プロパティとして直接に満たします。両方のクラスは、正しく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
インスタンスを含んでいる配列リテラル;平方キロメートルでの英国の面積で初期化されるCountry
インスタンス;そして、4本脚のAnimal
インスタンス;を含んでいる配列リテラルで初期化されます。
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(面積は、12.5663708です)
- // Area is 243610.0(面積は、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 that inherit from Objective-C classes or other @objc
classes. They can’t be adopted by structures or enumerations.
あなたは、オプショナル要件をプロトコルに対して定義できます。それらの要件は、そのプロトコルに準拠する型によって実装される必要はありません。オプショナルの要件は、そのプロトコル定義においてoptional
修飾子を前に置かれます。オプショナル要件が利用可能なことから、あなたはObjective-Cと相互運用するコードを書くことができます。プロトコルとオプショナル要件の両方は、@objc
属性で印されなければなりません。@objc
プロトコルがObjective-Cクラスや他の@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
プロトコルは、incrementForCount(_:)
と呼ばれるオプショナルのメソッド要件と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:)
を呼ぶことを試みます、そしてメソッドのもつただ1つの引数として現在のcount
値を渡します。
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つの階層のオプショナル連鎖が働いていることに注意してください。第1に、dataSource
がnil
かもしれない可能性があります、なので、dataSource
はその名前の後に疑問符を持ち、dataSource
がnil
でない場合にのみincrement(forCount:)
が呼ばれるべきであるのを示します。第2に、たとえ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
値を返します。たとえincrement(forCount:)
がCounterDataSource
の定義の中で非オプショナルの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.
値をincrement(forCount:)
メソッドから取り出すことが可能でないならば ― dataSource
がnilであるから、またはデータ・ソースがincrement(forCount:)
を実装しないからのどちらでも ― その時increment()
メソッドはその代わりに値をデータ・ソースのfixedIncrement
プロパティから取り出そうとします。fixedIncrement
プロパティもまたオプショナルの要件です、なのでその値はオプショナルのInt
値です、たとえfixedIncrement
が非オプショナルのInt
プロパティであるとCounterDataSource
プロトコル定義の部分では定義されるとしてもです。
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:
ある単純なCounterDataSource
実装がここにあります、そこにおいて、データ・ソースは3
の定数値をそれが問い合わされるたびに返します。それは、オプショナルの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
インスタンスであるように設定します;そして、counterのincrement()
メソッドを4回呼び出します。予想されるように、counterのcount
プロパティは、increment()
が呼ばれるたびに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がゼロに達するならば、それ以上数えることは起こりません:
- 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
プロトコルは拡張されてrandomBool()
メソッドを提供することができます、それは必須メソッドのrandom()
を利用してランダムなBool
値を返すものです:
- 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"(「ここに任意の数: 0.3746499199817101があります」を出力します)
- print("And here's a random Boolean: \(generator.randomBool())")
- // Prints "And here's a random Boolean: true"(「そしてここに任意のブール: 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
プロトコルを継承するprettyTextualDescription
プロパティは、それの必須プロパティ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 standard library, you can use the ==
and !=
operators to check for equality and inequality between two elements.
例えば、それの要素がEquatable
プロトコルに準拠するあらゆるコレクションに適用されるCollection
プロトコルに対して、あなたはある拡張を定義できます。あるコレクションの持つ要素をEquatable
プロトコル、標準ライブラリの1つ、に制約することで、あなたは==
と!=
演算子を使って同等性と同一性を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つの配列を考えてください、すべての要素が同じであるもの、そしてそうではないもの:
- 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"(「true」を出力します)
- print(differentNumbers.allEqual())
- // Prints "false"(「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. ある準拠型が同じメソッドやプロパティに対する実装を提供する複数の制約拡張に対する要件を満たすならば、スウィフトは最も特殊化した制約と一致する実装を使います。