下記URLから引用し、日本語訳をつけてみました。
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/guidedtour
Explore the features and syntax of Swift.
Swift の機能と構文を探ります。
Tradition suggests that the first program in a new language should print the words “Hello, world!” on the screen. In Swift, this can be done in a single line:
伝統的に、新しい言語での最初のプログラムでは「Hello, world!」という単語を出力する必要があるとされています。 画面上。 Swift では、これを 1 行で実行できます。
print("Hello, world!")
// Prints "Hello, world!"
This syntax should look familiar if you know another language — in Swift, this line of code is a complete program. You don’t need to import a separate library for functionality like outputting text or handling strings. Code written at global scope is used as the entry point for the program, so you don’t need a main()
function. You also don’t need to write semicolons at the end of every statement.
他の言語を知っている人なら、この構文はおなじみのはずです。Swift では、このコード行は完全なプログラムです。テキストの出力や文字列の処理などの機能のために別のライブラリをインポートする必要はありません。グローバル スコープで記述されたコードはプログラムのエントリ ポイントとして使用されるため、main()
関数は必要ありません。また、すべてのステートメントの最後にセミコロンを記述する必要もありません。
This tour gives you enough information to start writing code in Swift by showing you how to accomplish a variety of programming tasks. Don’t worry if you don’t understand something — everything introduced in this tour is explained in detail in the rest of this book.
このツアーでは、さまざまなプログラミング タスクを実行する方法を示し、Swift でコードを書き始めるのに十分な情報を提供します。理解できないことがあっても心配しないでください。このツアーで紹介された内容はすべて、この本の残りの部分で詳しく説明されています。
Simple Values
単純な値
Use let
to make a constant and var
to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.
定数を作成するには let を使用し、変数を作成するには var を使用します。 定数の値はコンパイル時にわかっている必要はありませんが、値を 1 回だけ割り当てる必要があります。 これは、定数を使用して、一度決定した後でさまざまな場所で使用する値に名前を付けることができることを意味します。
var myVariable = 42
myVariable = 50
let myConstant = 42
A constant or variable must have the same type as the value you want to assign to it. However, you don’t always have to write the type explicitly. Providing a value when you create a constant or variable lets the compiler infer its type. In the example above, the compiler infers that myVariable
is an integer because its initial value is an integer.
定数または変数は、割り当てたい値と同じ型でなければなりません。 ただし、必ずしも型を明示的に記述する必要はありません。 定数または変数を作成するときに値を指定すると、コンパイラーはその型を推測します。 上記の例では、myVariable の初期値が整数であるため、コンパイラは myVariable が整数であると推論します。
If the initial value doesn’t provide enough information (or if there isn’t an initial value), specify the type by writing it after the variable, separated by a colon.
初期値では十分な情報が得られない場合 (または初期値がない場合)、変数の後にコロンで区切って型を記述します。
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
Experiment
試してみよう
Create a constant with an explicit type of Float
and a value of 4
.
明示的な型が Float で値が 4 の定数を作成してみて。
Values are never implicitly converted to another type. If you need to convert a value to a different type, explicitly make an instance of the desired type.
値が暗黙的に別の型に変換されることはありません。 値を別の型に変換する必要がある場合は、目的の型のインスタンスを明示的に作成します。
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
Experiment
試してみよう
Try removing the conversion to String
from the last line. What error do you get?
最後の行から String を削除してみてください。 どのようなエラーが発生しますか?
There’s an even simpler way to include values in strings: Write the value in parentheses, and write a backslash (\
) before the parentheses. For example:
文字列に値を含めるさらに簡単な方法があります。値を括弧内に記述し、括弧の前にバックスラッシュ (\
) を記述します。 例えば:
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
Experiment
試してみよう
Use \()
to include a floating-point calculation in a string and to include someone’s name in a greeting.
\
() を使用すると、文字列に浮動小数点計算を含めたり、挨拶に誰かの名前を含めたりできます。
Use three double quotation marks ("""
) for strings that take up multiple lines. Indentation at the start of each quoted line is removed, as long as it matches the indentation of the closing quotation marks. For example:
複数行にわたる文字列には、3 つの二重引用符 ("""
) を使用します。引用符で囲まれた各行の先頭のインデントは、閉じ引用符のインデントと一致する限り削除されます。次に例を示します。
let quotation = """
Even though there's whitespace to the left,
the actual lines aren't indented.
Except for this line.
Double quotes (") can appear without being escaped.
I still have \(apples + oranges) pieces of fruit.
"""
Create arrays and dictionaries using brackets ([]
), and access their elements by writing the index or key in brackets. A comma is allowed after the last element.
角かっこ ([]
) を使用して配列と辞書を作成し、角かっこ内にインデックスまたはキーを記述することでそれらの要素にアクセスします。 最後の要素の後にはカンマを使用できます。
var fruits = ["strawberries", "limes", "tangerines"]
fruits[1] = "grapes"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
Arrays automatically grow as you add elements.
要素を追加すると、配列は自動的に拡大します。
fruits.append("blueberries")
print(fruits)
// Prints "["strawberries", "grapes", "tangerines", "blueberries"]"
You also use brackets to write an empty array or dictionary. For an array, write []
, and for a dictionary, write [:]
.
また、括弧を使用して空の配列または辞書を記述することもできます。 配列の場合は[]
、辞書の場合は[:]
と記述します。
fruits = []
occupations = [:]
If you’re assigning an empty array or dictionary to a new variable, or another place where there isn’t any type information, you need to specify the type.
空の配列またはディクショナリを新しい変数、または型情報のない別の場所に割り当てる場合は、型を指定する必要があります。
let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]
Control Flow
制御フロー
Use if
and switch
to make conditionals, and use for
–in
, while
, and repeat
–while
to make loops. Parentheses around the condition or loop variable are optional. Braces around the body are required.
if
と switch
を使用して条件文を作成し、for-in
、while
、repeat-while
を使用してループを作成します。 条件変数またはループ変数を囲むかっこはオプションです。 本体の周囲に中括弧{}が必要です。
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)
// Prints "11"
In an if
statement, the conditional must be a Boolean expression — this means that code such as if score { ... }
is an error, not an implicit comparison to zero.
if
ステートメントでは、条件はブール式である必要があります。これは、 if score { ... }
などのコードはエラーであり、ゼロとの暗黙の比較ではないことを意味します。
You can write if
or switch
after the equal sign (=
) of an assignment or after return
, to choose a value based on the condition.
代入の等号 (=
) の後、または return
の後に if
または switch
を記述して、条件に基づいて値を選択できます。
let scoreDecoration = if teamScore > 10 {
"🎉"
} else {
""
}
print("Score:", teamScore, scoreDecoration)
// Prints "Score: 11 🎉"
You can use if
and let
together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil
to indicate that a value is missing. Write a question mark (?
) after the type of a value to mark the value as optional.
if
と let
を一緒に使用すると、欠落している可能性のある値を処理できます。 これらの値はオプショナルとして表されます。 オプショナル値には、値が含まれるか、値が欠落していることを示す nil
が含まれます。 値をオプショナルとしてマークするには、値の型の後に疑問符 (?
) を記述します。
var optionalString: String? = "Hello"
print(optionalString == nil)
// Prints "false"
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
Experiment
試してみよう
Change optionalName
to nil
. What greeting do you get? Add an else
clause that sets a different greeting if optionalName
is nil
.
optionalName
を nil
に変更します。 どのような挨拶をしますか? optionsName
が nil
の場合に別の挨拶を設定する else
句を追加します。
If the optional value is nil
, the conditional is false
and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let
, which makes the unwrapped value available inside the block of code.
オプショナル値が nil
の場合、条件は false
になり、中括弧内のコードはスキップされます。 それ以外の場合、オプション値はラップ解除されて let
の後の定数に割り当てられ、ラップ解除された値がコード ブロック内で使用できるようになります。
Another way to handle optional values is to provide a default value using the ??
operator. If the optional value is missing, the default value is used instead.
オプショナル値を処理するもう 1 つの方法は、??
を使用してデフォルト値を指定することです。 オペレーター。 オプショナル値が欠落している場合は、代わりにデフォルト値が使用されます。
let nickname: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickname ?? fullName)"
You can use a shorter spelling to unwrap a value, using the same name for that unwrapped value.
より短いスペルを使用して値をアンラップし、そのアンラップされた値に同じ名前を使用できます。
if let nickname {
print("Hey, \(nickname)")
}
// Doesn't print anything, because nickname is nil.
Switches support any kind of data and a wide variety of comparison operations — they aren’t limited to integers and tests for equality.
スイッチは、整数や等価性のテストに限定されず、あらゆる種類のデータとさまざまな比較演算をサポートします。
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
// Prints "Is it a spicy red pepper?"
Experiment
試してよう
Try removing the default case. What error do you get?
デフォルトのケースを削除してみてください。 どのようなエラーが発生しますか?
Notice how let
can be used in a pattern to assign the value that matched the pattern to a constant.
パターン内で let
を使用して、パターンに一致した値を定数に割り当てる方法に注目してください。
After executing the code inside the switch case that matched, the program exits from the switch statement. Execution doesn’t continue to the next case, so you don’t need to explicitly break out of the switch at the end of each case’s code.
一致する switch case 内のコードを実行した後、プログラムは switch ステートメントを終了します。 実行は次のケースに続行されないため、各ケースのコードの最後にあるスイッチから明示的に抜け出す必要はありません。
You use for
–in
to iterate over items in a dictionary by providing a pair of names to use for each key-value pair. Dictionaries are an unordered collection, so their keys and values are iterated over in an arbitrary order.
for-in
を使用すると、各キーと値のペアに使用する名前のペアを指定して、辞書内の項目を反復処理できます。 ディクショナリは順序付けされていないコレクションであるため、そのキーと値は任意の順序で反復されます。
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (_, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
print(largest)
// Prints "25"
Experiment
試してみよう
Replace the _
with a variable name, and keep track of which kind of number was the largest.
_ を変数名に置き換えて、どの種類の数値が最大であったかを記録します。
Use while
to repeat a block of code until a condition changes. The condition of a loop can be at the end instead, ensuring that the loop is run at least once.
while
を使用して、条件が変わるまでコードのブロックを繰り返します。 代わりにループの条件を最後に指定して、ループが少なくとも 1 回実行されるようにすることができます。
var n = 2
while n < 100 {
n *= 2
}
print(n)
// Prints "128"
var m = 2
repeat {
m *= 2
} while m < 100
print(m)
// Prints "128"
Experiment
試してみよう
Change the condition from m < 100
to m < 0
to see how while
and repeat
–while
behave differently when the loop condition is already true.
条件を m < 100
から m < 0
に変更して、ループ条件がすでに true
の場合に while
とrepeat-while
の動作がどのように異なるかを確認します。
You can keep an index in a loop by using ..<
to make a range of indexes.
..<
を使用してインデックスの範囲を作成すると、ループ内にインデックスを保持できます。
var total = 0
for i in 0..<4 {
total += i
}
print(total)
// Prints "6"
Use ..<
to make a range that omits its upper value, and use ...
to make a range that includes both values.
上限値を省略した範囲を作成するには ..<
を使用し、両方の値を含む範囲を作成するには
を使用します。...
Functions and Closures
関数とクロージャ(関数閉包)
Use func
to declare a function. Call a function by following its name with a list of arguments in parentheses. Use ->
to separate the parameter names and types from the function’s return type.
関数を宣言するには func
を使用します。 関数名に続けて括弧内の引数のリストを指定して、関数を呼び出します。 ->
を使用して、パラメーターの名前と型を関数の戻り値の型から分離します。
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")
Experiment
試してみよう
Remove the day
parameter. Add a parameter to include today’s lunch special in the greeting.
day
パラメータを削除します。 パラメーターを追加して、今日の特別ランチを挨拶文に含めます。
By default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _
to use no argument label.
デフォルトでは、関数はパラメータ名を引数のラベルとして使用します。 パラメータ名の前にカスタム引数ラベルを書き込むか、引数ラベルを使用しない場合は _ を書きます。
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
Use a tuple to make a compound value — for example, to return multiple values from a function. The elements of a tuple can be referred to either by name or by number.
タプルを使用して複合値を作成します。たとえば、関数から複数の値を返します。 タプルの要素は、名前または番号で参照できます。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
// Prints "120"
print(statistics.2)
// Prints "120"
Functions can be nested. Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that’s long or complex.
関数は入れ子にすることができます。 ネストされた関数は、外側の関数で宣言された変数にアクセスできます。 ネストされた関数を使用すると、長い関数または複雑な関数のコードを整理できます。
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
Functions are a first-class type. This means that a function can return another function as its value.
関数はファーストクラスの型です。 これは、関数が別の関数を値として返すことができることを意味します。
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
A function can take another function as one of its arguments.
関数は、引数の 1 つとして別の関数を取ることができます。
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
Functions are actually a special case of closures: blocks of code that can be called later. The code in a closure has access to things like variables and functions that were available in the scope where the closure was created, even if the closure is in a different scope when it’s executed — you saw an example of this already with nested functions. You can write a closure without a name by surrounding code with braces ({}
). Use in
to separate the arguments and return type from the body.
関数は実際にはクロージャの特殊なケースであり、後で呼び出すことができるコードのブロックです。 クロージャ内のコードは、実行時にクロージャが別のスコープにある場合でも、クロージャが作成されたスコープで使用可能な変数や関数などにアクセスできます。この例は、ネストされた関数ですでに見ました。 コードを中括弧 ({}
) で囲むことにより、名前なしでクロージャを作成できます。 in
を使用して、引数と戻り値の型を本体から分離します。
numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
Experiment
試してみよう
Rewrite the closure to return zero for all odd numbers.
すべての奇数に対してゼロを返すようにクロージャを書き換えます。
You have several options for writing closures more concisely. When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both. Single statement closures implicitly return the value of their only statement.
クロージャをより簡潔に記述するためのオプションがいくつかあります。 デリゲートのコールバックなど、クロージャの型がすでにわかっている場合は、パラメータの型、戻り値の型、またはその両方を省略できます。 単一ステートメントのクロージャは、その唯一のステートメントの値を暗黙的に返します。
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
// Prints "[60, 57, 21, 36]"
You can refer to parameters by number instead of by name — this approach is especially useful in very short closures. A closure passed as the last argument to a function can appear immediately after the parentheses. When a closure is the only argument to a function, you can omit the parentheses entirely.
パラメータを名前ではなく番号で参照できます。このアプローチは、非常に短いクロージャで特に便利です。 関数の最後の引数として渡されるクロージャーは、かっこの直後に出現できます。 クロージャが関数の唯一の引数である場合は、括弧を完全に省略できます。
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
// Prints "[20, 19, 12, 7]"
Objects and Classes
オブジェクトとクラス
Use class
followed by the class’s name to create a class. A property declaration in a class is written the same way as a constant or variable declaration, except that it’s in the context of a class. Likewise, method and function declarations are written the same way.
クラスを作成するには、class の後にクラス名を続けて使用します。 クラス内のプロパティ宣言は、クラスのコンテキスト内にあることを除いて、定数または変数の宣言と同じ方法で記述されます。 同様に、メソッドと関数の宣言も同じ方法で記述されます。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
Experiment
試してみよう
Add a constant property with let
, and add another method that takes an argument.
let
で定数プロパティを追加し、引数を取る別のメソッドを追加します。
Create an instance of a class by putting parentheses after the class name. Use dot syntax to access the properties and methods of the instance.
クラス名の後にかっこを付けて、クラスのインスタンスを作成します。 ドット構文を使用して、インスタンスのプロパティとメソッドにアクセスします。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
This version of the Shape
class is missing something important: an initializer to set up the class when an instance is created. Use init
to create one.
このバージョンの Shape
クラスには、インスタンスの作成時にクラスを設定するための初期化子という重要な要素が欠落しています。 init
を使用して作成します。
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
Notice how self
is used to distinguish the name
property from the name
argument to the initializer. The arguments to the initializer are passed like a function call when you create an instance of the class. Every property needs a value assigned — either in its declaration (as with numberOfSides
) or in the initializer (as with name
).
name
プロパティとイニシャライザへの name
引数を区別するために self
がどのように使用されるかに注目してください。 イニシャライザへの引数は、クラスのインスタンスを作成するときに関数呼び出しのように渡されます。 すべてのプロパティには、その宣言 (numberOfSides
など) または初期化子 (name
など) のいずれかで、値を割り当てる必要があります。
Use deinit
to create a deinitializer if you need to perform some cleanup before the object is deallocated.
オブジェクトの割り当てが解除される前にクリーンアップを実行する必要がある場合は、deinit を使用して初期化解除子を作成します。
Subclasses include their superclass name after their class name, separated by a colon. There’s no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.
サブクラスには、クラス名の後にコロンで区切られたスーパークラス名が含まれます。 クラスが標準ルート クラスをサブクラス化する必要はないため、必要に応じてスーパークラスを含めたり省略したりできます。
Methods on a subclass that override the superclass’s implementation are marked with override
— overriding a method by accident, without override
, is detected by the compiler as an error. The compiler also detects methods with override
that don’t actually override any method in the superclass.
スーパークラスの実装をオーバーライドするサブクラスのメソッドにはoverride
のマークが付けられます。override
無しに偶然メソッドをオーバーライドすると、コンパイラーによってエラーとして検出されます。 コンパイラは、スーパークラス内のメソッドを実際にはオーバーライドしないoverride
のあるメソッドも検出します。
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
Experiment
試してみよう
Make another subclass of NamedShape
called Circle
that takes a radius and a name as arguments to its initializer. Implement an area()
and a simpleDescription()
method on the Circle
class.
初期化子への引数として半径と名前を取る Circle
という NamedShape
の別のサブクラスを作成します。 Circle
クラスに area()
メソッドと simpleDescription()
メソッドを実装します。
In addition to simple properties that are stored, properties can have a getter and a setter.
保存される単純なプロパティに加えて、プロパティにはゲッターとセッターを含めることができます。
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
// Prints "9.3"
triangle.perimeter = 9.9
print(triangle.sideLength)
// Prints "3.3000000000000003"
In the setter for perimeter
, the new value has the implicit name newValue
. You can provide an explicit name in parentheses after set
.
perimeter
のセッターでは、新しい値には暗黙的な名前 newValue が付けられます。 設定した後に括弧内に明示的な名前を指定できます。
Notice that the initializer for the EquilateralTriangle
class has three different steps:
EquiliteralTriangle
クラスの初期化子には 3 つの異なるステップがあることに注意してください。
1.Setting the value of properties that the subclass declares.
1.サブクラスが宣言するプロパティの値を設定します。
2.Calling the superclass’s initializer.
2.スーパークラスのイニシャライザを呼び出します。
3.Changing the value of properties defined by the superclass. Any additional setup work that uses methods, getters, or setters can also be done at this point.
3.スーパークラスによって定義されたプロパティの値を変更します。 メソッド、ゲッター、またはセッターを使用する追加のセットアップ作業もこの時点で行うことができます。
If you don’t need to compute the property but still need to provide code that’s run before and after setting a new value, use willSet
and didSet
. The code you provide is run any time the value changes outside of an initializer. For example, the class below ensures that the side length of its triangle is always the same as the side length of its square.
プロパティを計算する必要はないが、新しい値を設定する前後に実行されるコードを提供する必要がある場合は、willSet
と didSet
を使用します。 提供したコードは、イニシャライザの外部で値が変更されるたびに実行されます。 たとえば、以下のクラスは、三角形の辺の長さが常に正方形の辺の長さと同じであることを保証します。
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
// Prints "10.0"
print(triangleAndSquare.triangle.sideLength)
// Prints "10.0"
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
// Prints "50.0"
When working with optional values, you can write ?
before operations like methods, properties, and subscripting. If the value before the ?
is nil
, everything after the ?
is ignored and the value of the whole expression is nil
. Otherwise, the optional value is unwrapped, and everything after the ?
acts on the unwrapped value. In both cases, the value of the whole expression is an optional value.
オプショナル値を扱うときは、?
と書くことができます。 メソッド、プロパティ、添え字などの操作の前。 ?
の前の値が nil
の場合、?
以降はすべて は無視され、式全体の値は nil
になります。 それ以外の場合、オプショナル値はラップされず、?
以降のすべてがラップされます。 アンラップされた値に作用します。 どちらの場合も、式全体の値はオプショナル値です。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
Enumerations and Structures
列挙と構造
Use enum
to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.
enum を使用して列挙を作成します。 クラスや他のすべての名前付き型と同様に、列挙型にはメソッドを関連付けることができます。
enum Rank: Int {
case ace = 1
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
func simpleDescription() -> String {
switch self {
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
case .king:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
Experiment
試してみよう
Write a function that compares two Rank
values by comparing their raw values.
生の値を比較することによって 2 つのRank
値を比較する関数を作成します。
By default, Swift assigns the raw values starting at zero and incrementing by one each time, but you can change this behavior by explicitly specifying values. In the example above, Ace
is explicitly given a raw value of 1
, and the rest of the raw values are assigned in order. You can also use strings or floating-point numbers as the raw type of an enumeration. Use the rawValue
property to access the raw value of an enumeration case.
デフォルトでは、Swift はゼロから始まり毎回 1 ずつ増加する生の値を割り当てますが、値を明示的に指定することでこの動作を変更できます。 上の例では、Ace
には生の値 1
が明示的に与えられ、残りの生の値が順番に割り当てられます。 文字列または浮動小数点数を列挙の生の型として使用することもできます。 rawValue
プロパティを使用して、列挙型caseの生の値にアクセスします。
Use the init?(raw
initializer to make an instance of an enumeration from a raw value. It returns either the enumeration case matching the raw value or nil
if there’s no matching Rank
.
init?(rawValue:)
イニシャライザを使用して、生の値から列挙型のインスタンスを作成します。 生の値に一致する列挙型caseを返すか、一致するRank
がない場合は nil
を返します。
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
}
The case values of an enumeration are actual values, not just another way of writing their raw values. In fact, in cases where there isn’t a meaningful raw value, you don’t have to provide one.
列挙型のcase値は実際の値であり、生の値を別の方法で記述するものではありません。 実際、意味のある生の値がない場合は、値を指定する必要はありません。
enum Suit {
case spades, hearts, diamonds, clubs
func simpleDescription() -> String {
switch self {
case .spades:
return "spades"
case .hearts:
return "hearts"
case .diamonds:
return "diamonds"
case .clubs:
return "clubs"
}
}
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
Experiment
試してみよう
Add a color()
method to Suit
that returns “black” for spades and clubs, and returns “red” for hearts and diamonds.
スペードとクラブの場合は「黒」を返し、ハートとダイヤモンドの場合は「赤」を返す color()
メソッドをSuit
に追加します。
Notice the two ways that the hearts
case of the enumeration is referred to above: When assigning a value to the hearts
constant, the enumeration case Suit.hearts
is referred to by its full name because the constant doesn’t have an explicit type specified. Inside the switch, the enumeration case is referred to by the abbreviated form .hearts
because the value of self
is already known to be a suit. You can use the abbreviated form anytime the value’s type is already known.
上記で列挙型のhearts
のcaseが参照されている 2 つの方法に注目してください。hearts
定数に値を割り当てる場合、定数には明示的な型が指定されていないため、列挙型caseのSuit.hearts
は完全名で参照されます。 switch内では、self
の値がスーツであることがすでにわかっているため、列挙caseは省略形 .hearts
で参照されます。 値の型がすでにわかっている場合は、いつでも省略形を使用できます。
If an enumeration has raw values, those values are determined as part of the declaration, which means every instance of a particular enumeration case always has the same raw value. Another choice for enumeration cases is to have values associated with the case — these values are determined when you make the instance, and they can be different for each instance of an enumeration case. You can think of the associated values as behaving like stored properties of the enumeration case instance. For example, consider the case of requesting the sunrise and sunset times from a server. The server either responds with the requested information, or it responds with a description of what went wrong.
列挙に生の値がある場合、それらの値は宣言の一部として決定されます。これは、特定の列挙caseのすべてのインスタンスが常に同じ生の値を持つことを意味します。 列挙caseのもう 1 つの選択肢は、caseに関連付けられた値を持つことです。これらの値はインスタンスの作成時に決定され、列挙caseのインスタンスごとに異なる値にすることができます。 関連する値は、列挙型case インスタンスの保存されたプロパティのように動作すると考えることができます。 たとえば、サーバーに日の出と日の入りの時刻をリクエストする場合を考えてみましょう。 サーバーは、要求された情報で応答するか、何が問題だったかの説明で応答します。
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
}
// Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."
Experiment
試してみよう
Add a third case to ServerResponse
and to the switch.
3 番目のcaseを ServerResponse
とswitchに追加します。
Notice how the sunrise and sunset times are extracted from the ServerResponse
value as part of matching the value against the switch cases.
値をswitchのcaseと照合する一環として、ServerResponse
値から日の出と日の入りの時刻がどのように抽出されるかに注目してください。
Use struct
to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they’re passed around in your code, but classes are passed by reference.
構造体を作成するには struct
を使用します。 構造体は、メソッドや初期化子など、クラスと同じ動作の多くをサポートします。 構造体とクラスの最も重要な違いの 1 つは、構造体はコード内で渡されるときに常にコピーされるのに対し、クラスは参照によって渡されることです。
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
Experiment
試してみよう
Write a function that returns an array containing a full deck of cards, with one card of each combination of rank and suit.
rankとsuitの組み合わせごとに 1 枚のカードを含む、カードの完全なデッキを含む配列を返す関数を作成します。
Concurrency
同時実行性
Use async
to mark a function that runs asynchronously.
async
を使用して、非同期で実行される関数をマークします。
func fetchUserID(from server: String) async -> Int {
if server == "primary" {
return 97
}
return 501
}
You mark a call to an asynchronous function by writing await
in front of it.
非同期関数の呼び出しをマークするには、関数の前に await
を記述します。
func fetchUsername(from server: String) async -> String {
let userID = await fetchUserID(from: server)
if userID == 501 {
return "John Appleseed"
}
return "Guest"
}
Use async let
to call an asynchronous function, letting it run in parallel with other asynchronous code. When you use the value it returns, write await
.
async let
を使用して非同期関数を呼び出し、他の非同期コードと並行して実行できるようにします。 返される値を使用する場合は、「await
」と書き込みます。
func connectUser(to server: String) async {
async let userID = fetchUserID(from: server)
async let username = fetchUsername(from: server)
let greeting = await "Hello \(username), user ID \(userID)"
print(greeting)
}
Use Task
to call asynchronous functions from synchronous code, without waiting for them to return.
Task
を使用すると、非同期関数が返されるのを待たずに、同期コードから非同期関数を呼び出します。
Task {
await connectUser(to: "primary")
}
// Prints "Hello Guest, user ID 97"
Use task groups to structure concurrent code.
タスク グループを使用して同時コードを構造化します。
let userIDs = await withTaskGroup(of: Int.self) { taskGroup in
for server in ["primary", "secondary", "development"] {
taskGroup.addTask {
return await fetchUserID(from: server)
}
}
var results: [Int] = []
for await result in taskGroup {
results.append(result)
}
return results
}
Actors are similar to classes, except they ensure that different asynchronous functions can safely interact with an instance of the same actor at the same time.
Actorはクラスに似ていますが、異なる非同期関数が同時に同じActorのインスタンスと安全に対話できるようにする点が異なります。
actor ServerConnection {
var server: String = "primary"
private var activeUsers: [Int] = []
func connect() async -> Int {
let userID = await fetchUserID(from: server)
// ... communicate with server ...
activeUsers.append(userID)
return userID
}
}
When you call a method on an actor or access one of its properties, you mark that code with await
to indicate that it might have to wait for other code that’s already running on the actor to finish.
Actorのメソッドを呼び出すとき、またはそのプロパティの 1 つにアクセスするときは、そのコードに await
のマークを付けて、Actor上ですでに実行されている他のコードが終了するまで待機する必要がある可能性があることを示します。
let server = ServerConnection()
let userID = await server.connect()
Protocols and Extensions
プロトコルと拡張機能
Use protocol
to declare a protocol.
プロトコルを宣言するには、protocol
を使用します。
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
Classes, enumerations, and structures can all adopt protocols.
クラス、列挙、および構造はすべてプロトコルを採用できます。
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
Experiment
試してみよう
Add another requirement to ExampleProtocol
. What changes do you need to make to SimpleClass
and SimpleStructure
so that they still conform to the protocol?
ExampleProtocol
に別の要件を追加します。 SimpleClass
と SimpleStructure
をプロトコルに準拠させるには、どのような変更を加える必要がありますか?
Notice the use of the mutating
keyword in the declaration of SimpleStructure
to mark a method that modifies the structure. The declaration of SimpleClass
doesn’t need any of its methods marked as mutating because methods on a class can always modify the class.
SimpleStructure
の宣言で、構造を変更するメソッドをマークするために mutating
キーワードが使用されていることに注目してください。 クラスのメソッドはいつでもクラスを変更できるため、SimpleClass
の宣言では、変更可能としてマークされたメソッドは必要ありません。
Use extension
to add functionality to an existing type, such as new methods and computed properties. You can use an extension to add protocol conformance to a type that’s declared elsewhere, or even to a type that you imported from a library or framework.
extension
を使用して、新しいメソッドや計算されたプロパティなどの機能を既存の型に追加します。 拡張機能を使用すると、他の場所で宣言された型、またはライブラリやフレームワークからインポートした型にプロトコル準拠を追加できます。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
// Prints "The number 7"
Experiment
試してみよう
Write an extension for the Double
type that adds an absoluteValue
property.
AbsoluteValue
プロパティを追加する Double
型の拡張機能を作成します。
You can use a protocol name just like any other named type — for example, to create a collection of objects that have different types but that all conform to a single protocol. When you work with values whose type is a boxed protocol type, methods outside the protocol definition aren’t available.
プロトコル名は、他の名前付き型と同じように使用できます。たとえば、型は異なるが、すべてが 1 つのプロトコルに準拠するオブジェクトのコレクションを作成できます。 タイプがボックス化されたプロトコルタイプである値を操作する場合、プロトコル定義外のメソッドは使用できません。
let protocolValue: any ExampleProtocol = a
print(protocolValue.simpleDescription)
// Prints "A very simple class. Now 100% adjusted."
// print(protocolValue.anotherProperty) // Uncomment to see the error
Even though the variable protocolValue
has a runtime type of SimpleClass
, the compiler treats it as the given type of ExampleProtocol
. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.
変数protocolValue
のランタイム型はSimpleClass
ですが、コンパイラはそれをExampleProtocol
の指定された型として扱います。 これは、プロトコルへの準拠に加えてクラスが実装するメソッドやプロパティに誤ってアクセスできないことを意味します。
Error Handling
エラー処理
You represent errors using any type that adopts the Error
protocol.
エラーは、Error
プロトコルを採用する任意の型を使用して表します。
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
Use throw
to throw an error and throws
to mark a function that can throw an error. If you throw an error in a function, the function returns immediately and the code that called the function handles the error.
エラーをスローするには throw
を使用し、エラーをスローできる関数をマークするには throws
を使用します。 関数でエラーをスローした場合、関数はすぐに戻り、関数を呼び出したコードがエラーを処理します。
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
There are several ways to handle errors. One way is to use do
–catch
. Inside the do
block, you mark code that can throw an error by writing try
in front of it. Inside the catch
block, the error is automatically given the name error
unless you give it a different name.
エラーを処理するにはいくつかの方法があります。 1 つの方法は、do-catch
を使用することです。 do
ブロック内で、その前に try
を記述することで、エラーをスローする可能性のあるコードをマークします。 catch
ブロック内では、別の名前を付けない限り、エラーには自動的に error
という名前が付けられます。
do {
let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
print(printerResponse)
} catch {
print(error)
}
// Prints "Job sent"
Experiment
試してみよう
Change the printer name to "Never Has Toner"
, so that the send(job:toPrinter:)
function throws an error.
プリンター名を"Never Has Toner"
に変更すると、send(job:toPrinter:)
関数がエラーをスローします。
You can provide multiple catch
blocks that handle specific errors. You write a pattern after catch
just as you do after case
in a switch.
特定のエラーを処理する複数の catch
ブロックを提供できます。 switch の case
の後にパターンを記述するのと同じように、catch
の後にパターンを記述します。
Experiment
試してみよう
Add code to throw an error inside the do
block. What kind of error do you need to throw so that the error is handled by the first catch
block? What about the second and third blocks?
do
ブロック内にエラーをスローするコードを追加します。 最初の catch
ブロックでエラーが処理されるようにするには、どのような種類のエラーをスローする必要がありますか? 2番目と3番目のブロックはどうでしょうか?
Another way to handle errors is to use try?
to convert the result to an optional. If the function throws an error, the specific error is discarded and the result is nil
. Otherwise, the result is an optional containing the value that the function returned.
エラーを処理する別の方法は、try?
を使用することです。 結果をオプションに変換します。 関数がエラーをスローした場合、特定のエラーは破棄され、結果は nil
になります。 それ以外の場合、結果は関数が返した値を含むオプションです。
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
Use defer
to write a block of code that’s executed after all other code in the function, just before the function returns. The code is executed regardless of whether the function throws an error. You can use defer
to write setup and cleanup code next to each other, even though they need to be executed at different times.
defer
を使用して、関数内の他のすべてのコードの後で、関数が戻る直前に実行されるコード ブロックを記述します。 コードは、関数がエラーをスローするかどうかに関係なく実行されます。 defer
を使用すると、セットアップ コードとクリーンアップ コードを別の時間に実行する必要がある場合でも、並べて記述することができます。
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
if fridgeContains("banana") {
print("Found a banana")
}
print(fridgeIsOpen)
// Prints "false"
Generics
一般名
Write a name inside angle brackets to make a generic function or type.
山括弧内に名前を記述して、汎用関数または型を作成します。
func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
var result: [Item] = []
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
makeArray(repeating: "knock", numberOfTimes: 4)
You can make generic forms of functions and methods, as well as classes, enumerations, and structures.
クラス、列挙、構造体だけでなく、関数やメソッドの汎用形式も作成できます。
// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
case none
case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)
Use where
right before the body to specify a list of requirements — for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.
本文の直前に where
を使用して要件のリストを指定します。たとえば、型にプロトコルの実装を要求する、2 つの型が同じであることを要求する、またはクラスが特定のスーパークラスを持つことを要求するなどです。
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Element: Equatable, T.Element == U.Element
{
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])
Experiment
試してみよう
Modify the anyCommonElements(_:_:)
function to make a function that returns an array of the elements that any two sequences have in common.
anyCommonElements(_:_:)
関数を変更して、2 つのシーケンスに共通する要素の配列を返す関数を作成します。
Writing <T: Equatable>
is the same as writing <T> ... where T: Equatable
.
<T: Equatable>
を記述することは、<T> ... where T: Equatable
を記述することと同じです。。