Swift 5.8 日本語化計画 : Swift 5.8


Swift のツアー


伝統では、新しい言語で最初のプログラムは、スクリーンに "Hello,world !" という言葉を表示するものであるべきだと示唆しています。Swift では、これは単一の行で行うことができます。


  1. print("Hello, world!")
  2. // Prints "Hello,world!"


C や Objective-C でコードを書いた事がある場合、この構文は、おなじみに見えますが、Swift では、コードのこの行は完全なプログラムです。input/output、または文字列処理などの機能のために別のライブラリをインポートする必要はありません。グローバルスコープで書かれたコードは、プログラムのエントリポイントとして使用されているので、main() 関数は必要ありません。また、すべての文の末尾にセミコロンを書く必要もありません。


このツアーでは、色々なプログラミングのタスクを実行する方法を示すことによって、Swift でコードを書き始めるのに十分な情報を提供します。何かわからない事があっても心配しないで下さい。このツアーで紹介するすべてはこの本の残りの部分で詳しく説明されています。


注意: 最高の経験を得るために、Xcode でのプレイグラウンドとして、この章を開きましょう。プレイグラウンドでは、コードのリストを編集し、すぐに結果を確認することができます。

X-Code の File > New > Playground... を選択し、新たな Playground を作成して、以下のソースをペーストして試して欲しい。自然と Swift の文法が身に付くだろう。



単純な値


let で定数を作成し、var で変数を作成します。定数の値はコンパイル時に知っている必要はありませんが、一度だけ、それに値を代入しなければなりません。これは、一度決定するが、多くの場所で使用する値の名前に定数を使用できることを意味します。


  1. var   myVariable = 42
  2. myVariable = 50
  3. let  myConstant = 42


定数または変数は、それに代入したい値と同じ型を持たなければなりません。ただし、常に明示的に型を記述する必要はありません。定数や変数を作成して値を与えると、コンパイラはその型を推論します。上記の例では、コンパイラは、その初期値が整数であるため myVariable が整数であると推論します。


初期値が十分な情報を提供しない(または初期値が存在しない場合)、変数の後にコロンで区切って、型を書くことで指定して下さい。


  1. let  implicitInteger = 70
  2. let  implicitDouble = 70.0
  3. let  explicitDouble: Double = 70


実験: 明示的な Float 型で 4 の値を持つ定数を作成して下さい。

値は、別の型に暗黙的に変換されることは決してありません。別の型に値を変換する必要がある場合は、明示的に希望の型のインスタンスを作って下さい。


  1. let  label = "The width is "
  2. let  width = 94
  3. let  widthLabel = label + String(width)


実験: 最後の行から String への変換を削除してみてください。どのようなエラーが出ましたか?


文字列内に値を含むさらに簡単な方法があります。括弧内に値を書き、括弧の前にバックスラッシュ(\)を書きます。たとえば、次のように:


  1. let  apples = 3
  2. let  oranges = 5
  3. let  appleSummry = "I have \(apples) apples."
  4. let  fruitSummary = "I have \(apples + oranges) pieces of fruit."


実験: 文字列内に浮動小数点演算を含むように、また挨拶で誰かの名前が含まれるように \() を使用して下さい。


複数の行を取る文字列には 3 つの二重引用符(""") を使います。引用符で囲まれた行の先頭にあるインデントは、閉じた引用符のインデントに一致する限り削除されます。例えば:


  1. let  quotation = """
  2. I said "I have \(apples) apples."
  3. And then I said "I have \(apples + oranges) pieces of fruit."
  4. """


括弧([ ]) を使用して、配列や dictionary を作成し、括弧内にインデックスまたはキーを書き込むことによって、それらの要素にアクセスします。


  1. var fruits = ["strawberries", "limes", "tangerines"]
  2. fruits[1] = "grapes"
  3. var occupations = [
  4. "Malcolm": "Captain",
  5. "Kaylee": "Mechanic",
  6. ]
  7. occupations["Jayne"] = "Public Relations"


要素を追加すると配列は自動的に大きくなります。


  1. fruits.append("blueberries")
  2. print(fruits)
  3. // Prints "["strawberries", "grapes", "tangerines", "blueberries"]"


また、括弧を使用して、空の配列または辞書を記述します。配列の場合は []、辞書の場合は [:]と書きます。


  1. fruits = []
  2. occupations = [:]


空の配列または辞書を新しい変数、または型情報がない別の場所に割り当てる場合は、型を指定する必要があります。


  1. let emptyArray: [String] = []
  2. let emptyDictionary: [String: Float] = [:]


制御フロー


条件文を作るため、ifswitch を使い、for-in,while,及び repeat-while をループを作るために使用します。条件やループ変数用のの括弧はオプションです。本体の周りの中カッコは必須です。


  1. let  individualScores = [75, 43, 103, 87, 12]
  2. var  teamScore = 0
  3. for  score  in  individualScores {
  4. if score > 50 {
  5. teamScore += 3
  6. } else {
  7. teamScore += 1
  8. }
  9. }
  10. print(teamScore)
  11. // Prints "11"


if 文では、条件は ブール 式でなければならず、つまり、if score { ... } のようなコードはエラーであり、ゼロとの暗黙の比較ではありません。


欠落している可能性がある値を処理する場合に iflet とを共に使用できます。これらの値は optional として表されます。optional の値は、値を含むか、値が欠けていることを示すために nil を含みます。optional として値をマークする値の型の後に疑問符(?)を書いてください。


  1. var optionalString: String? = "Hello"
  2. print(optionalString == nil)
  3. // Prints "false"
  4. var  optionalName: String? = "John Appleseed"
  5. var  greeting = "Hello!"
  6. if  let  name = optionalName {
  7. greeting = "Hello, \(name)"
  8. }


実験:optionalName を変更して nil にします。何の挨拶をされましたか? optionalNamenil の場合、別の挨拶を設定するために else 節を追加して下さい。


optional の値が nil の場合、条件文は false であり、括弧内のコードはスキップされます。それ以外の場合、optional の値は開封され、コードブロック内の利用可能な開封値になり、これは let の後の定数に代入されます。


optional の値を処理するもう 1 つの方法は、?? 演算子を使用してデフォルト値を提供することです。optional の値が欠落している場合、デフォルト値が代わりに使用されます。


  1. let nickName: String? = nil
  2. let fullName: String = "John Appleseed"
  3. let informalGreeting = "Hi \(nickName ?? fullName)"


開封した同じ名前を使用して、より短いスペルを使用して値を開封できます。


  1. if let nickname {
  2. print("Hey, \(nickname)")
  3. }
  4. // Doesn't print anything, because nickname is nil.


Switch は、どんな種類のデータでもサポートし、広範囲の比較操作をサポートし、それらが等しいかどうかのテストは、整数に限定されません。


  1. let  vegetable = "red pepper"
  2. switch  vegetable {
  3. case  "celery":
  4. print("Add some raisins and make ants on a log.")
  5. case "cucumber", "watercress":
  6. print("That would make a good tea sandwich.")
  7. case let x where x.hasSuffix("pepper"):
  8. print("Is it a spicy \(x)?")
  9. default:
  10. print("Everything tastes good in soup.")
  11. }
  12. // Prints "Is it a spicy red pepper?"


実験: デフォルトのケースを削除してみてください。どのようなエラーが出るでしょう?


定数へのパターンが一致した値を代入するパターンで let がどのように使用できるかに注目しましょう​​。


一致した switch case 内のコードを実行した後、プログラムは switch 文を終了します。実行は、次の case に進みませんので、明示的にそれぞれの case のコードの最後に switch を break する必要はありません。


各キー値のペアで使用する名前のペアを提供することにより、dictionary 内の項目を反復処理するために、 for-in を使用して下さい。dictionary は順不同のコレクションであり、そのキー値は任意の順序で反復されます。


  1. let  interestingNumbers = [
  2. "Prime": [2, 3, 5, 7, 11, 13],
  3. "Fibonacci": [1, 1, 2, 3, 5, 8],
  4. "Square": [1, 4, 9, 16, 25],
  5. ]
  6. var largest = 0
  7. for  (_, numbers)  in interestingNumbers {
  8. for  number  in  numbers {
  9. if number > largest {
  10. largest = number
  11. }
  12. }
  13. }
  14. print(largest)
  15. Prints "25"


実験:_ を変数名に置き換え、どの種類の数値が最大であったかを追跡してみましょう。


条件が変化するまで、コードのブロックを繰り返すには while を使用します。ループが少なくとも一度実行されることを保証する代わりに、ループの条件を最後にすることができます。


  1. var  n = 2
  2. while  n < 100 {
  3. n *= 2
  4. }
  5. print(n)
  6. // Prints "128"
  7. var m  =  2
  8. repeat {
  9. m *= 2
  10. } while m <  100
  11. print(m)
  12. // Prints "128"


インデックスの範囲を作るために ..< を使用して、ループでインデックスを維持することができます。


  1. var total = 0
  2. for i in 0..<4 {
  3. total += i
  4. }
  5. print(total)
  6. // Prints "6"


..< を使って、上限の値を省略した範囲を作り、... を使って両方の値を含む範囲を作成します。


関数とクロージャ


関数を宣言するためには、func を使用してください。括弧内の引数のリストと、その名前に従うことで関数を呼び出します。-> を使って関数の戻り値の型からパラメータの名前と型を分離します。


  1. func greet(person: String, day: String) -> String {
  2. return "Hello \(person), today is \(day)."
  3. }
  4. greet(person:"Bob", day: "Tuesday")


実験: day のパラメータを削除して、特別な今日の昼食の挨拶が含まれるようにパラメータを追加してみましょう。

デフォルトでは、関数は引数用のラベルとして、それらのパラメータ名を使用します。パラメータ名の前にカスタム引数のラベルを書くか、または引数のラベルを使用しないように _ を書きます。


  1. func greet(_ person: String, on day: String) -> String {
  2. return "Hello \(person), today is \(day)."
  3. }
  4. greet("John", on: "Wednesday")


例えば、関数から複数の値を返すために、複雑な値を作るためにタプルを使用してください。タプルの要素は、名前または数字のいずれかで参照できます。


  1. func  calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
  2. var  min = scores[0]
  3. var  max = scores[0]
  4. var  sum = 0
  5. for  score  in  scores {
  6. if  score > max {
  7. max = score
  8. } else if score < min {
  9. min = score
  10. }
  11. sum += score
  12. }
  13. return (min, max, sum)
  14. }
  15. let  statistics = calculateStatistics(scores:[5, 3, 100, 3, 9])
  16. print(statistics.sum)
  17. // Prints "120"
  18. print(statistics.2)
  19. // Prints "120"


関数は入れ子にできます。入れ子にされた関数は、外部関数で宣言された変数にアクセスできます。入れ子にされた関数を使用して、長く複雑な関数のコードを整理できます。


  1. func returnFifteen() -> Int {
  2. var y = 10
  3. func add() {
  4. y += 5
  5. }
  6. add()
  7. return y
  8. }
  9. returnFifteen()


関数は最高級の型です。これは、関数がその値として別の関数を返せることを意味します。


  1. func  makeIncrementer() -> ((Int) -> Int) {
  2. func  addOne(number: Int) -> Int {
  3. return 1 + number
  4. }
  5. return addOne
  6. }
  7. var increment = makeIncrementer()
  8. increment(7)


関数は、別の関数を、引数の1つとして取ることができます。


  1. func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
  2. for item in list {
  3. if condition(item) {
  4. return true
  5. }
  6. }
  7. return false
  8. }
  9. func lessThanTen(number: Int) -> Bool {
  10. return number < 10
  11. }
  12. var numbers = [20, 19, 7, 12]
  13. hasAnyMatches(list: numbers, condition: lessThanTen)


関数は、実際にはクロージャ (後で呼び出すことができるコードのブロック) の特殊なケースです。クロージャのコードは、入れ子になった関数で既にこの例を見ていますが、実行されるときは別のスコープにクロージャがある場合でも、クロージャが作成されたスコープ内で使用可能な変数や関数のようなものにアクセスできます。中括弧({})を使用してコードを囲んで、名前のないクロージャを書くことができます。引数を分離し、本体から型を返すように in を使用して下さい。


  1. numbers.map({   (number: Int) -> Int in
  2. let result = 3 * number
  3. return result
  4. })


実験: すべての奇数でゼロを返すようにクロージャを書き換えてみましょう。


もっと簡潔にクロージャを書くためにいくつかのオプションがあります。クロージャの型が既に分かっている場合、デリゲートの呼び出し関数のように、そのパラメータ、その戻り値の型、または両方の型を省略できます。単一の文のクロージャは、暗黙のうちにそれらの唯一の文の値を返します。


  1. let mappedNumbers = numbers.map({ number in 3 * number })
  2. print(mappedNumbers)
  3. // Prints "[60, 57, 21, 36]"


名前の代わりに、番号で、パラメータを参照することができ、このアプローチは、非常に短いクロージャでは特に有用です。関数への最後の引数として渡されたクロージャは、括弧の直後に表示されることがあります。クロージャが関数の唯一の引数であるときは、かっこを完全に省略することができます。


  1. let sortedNumbers = numbers.sorted { $0 > $1 }
  2. print(sortedNumbers)
  3. // Prints "[20, 19, 12, 7]"


オブジェクトとクラス


クラスを作成するには、class の後にクラスの名前を続けて下さい。クラス内のプロパティの宣言は、クラスのコンテキスト内であることを除いては、定数または変数の宣言と同じように書かれます。同様に、メソッドおよび関数の宣言も、同じように書かれます。


  1. class Shape {
  2. var numberOfSides = 0
  3. func simpleDescription() -> String {
  4. return "A shape with \(numberOfSides) sides."
  5. }
  6. }


実験: let で定数のプロパティを追加して、引数を取る別のメソッドを追加してみましょう。


クラスの名前の後に括弧を書くことによって、クラスのインスタンスを作成します。プロパティとインスタンスのメソッドにアクセスするには、ドット構文を使用します。


  1. var shape = Shape()
  2. shape.numberOfSides = 7
  3. var shapeDescription = shape.simpleDescription()


Shape クラスのこのバージョンは、重要な何かが欠けています:インスタンスの作成時にクラスを設定するためのイニシャライザです。作成するには init を使用してください。


  1. class NamedShape {
  2. var numberOfSides: Int = 0
  3. var name: String
  4. init(name: String) {
  5.     self.name = name
  6. }
  7. func simpleDescription() -> String {
  8.     return "A shape with \(numberOfSides) sides."
  9. }
  10. }


イニシャライザへの name 引数から name プロパティを区別するために self がどのように使用されるかに注意してください。クラスのインスタンスを作成するときにイニシャライザへの引数は、関数呼び出しのように渡されます。すべてのプロパティは、その宣言(numberOfSides のように)内や、(name のように)イニシャライザ内のいずれかで値が割り当てられる必要があります。


オブジェクトが割り当て解除される前に何らかのクリーンアップを実行する必要がある場合は、デイニシャライザを作成するのに deinit を使用してください。


サブクラスは、コロンで区切られたクラス名の後に、それらのスーパークラスの名前を含みます。クラスは、標準的なルートクラスをサブクラス化する必要はなく、必要に応じてスーパークラスを省略したり含めたりできます。


スーパークラスの実装をオーバーライドするサブクラスのメソッドは override でマークされ、override なしで誤ってメソッドをオーバーライドすると、コンパイラによってエラーとして検出されます。コンパイラは、また実際にはスーパークラス内のどのメソッドもオーバーライドしない override でマークされたメソッドも検出します。


  1. class Square: NamedShape {
  2. var sideLength: Double
  3. init(sideLength: Double, name: String) {
  4.     self.sideLength = sideLength
  5. super.init(name: name)
  6. numberOfSides = 4
  7. }
  8. func area() -> Double {
  9. return sideLength * sideLength
  10. }
  11. override func simpleDescription() -> String {
  12.     return "A square with sides of length \(sideLength)."
  13. }
  14. }
  15. let test = Square(sideLength: 5.2, name: "my test square")
  16. test.area()
  17. test.simpleDescription()


実験: Circle と呼ばれる NamedShape の別のサブクラスを作成し、そのイニシャライザへの引数として半径と名前を取るものを作りましょう。Circle クラス上の area()simpleDescription() メソッドを実装しましょう。


保管されている単純なプロパティに加えて、プロパティは gettersetter を持つことができます。


  1. class EquilateralTriangle: NamedShape {
  2. var sideLength: Double = 0.0
  3. init(sideLength: Double, name: String) {
  4. self.sideLength = sideLength
  5. super.init(name: name)
  6. numberOfSides = 3
  7. }
  8. var perimeter: Double {
  9. get {
  10. return 3.0 * sideLength
  11. }
  12. set {
  13. sideLength = newValue / 3.0
  14. }
  15. }
  16. override func simpleDescription() -> String {
  17.        return "An equilateral triangle with sides of length \(sideLength)."
  18. }
  19. }
  20. var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
  21. print(triangle.perimeter)
  22. // Prints "9.3"
  23. triangle.perimeter = 9.9
  24. print(triangle.sideLength)
  25. // Prints "3.3000000000000003"


perimeter の setter では、新しい値は、暗黙の名前 newValue を持っています。set の後の括弧内に明示的な名前を提供できます。


EquilateralTriangle クラスのイニシャライザには、3つの異なる段階があることに注意してください:


  1. サブクラスが宣言したプロパティの値を設定します。
  2. スーパークラスのイニシャライザを呼び出します。
  3. スーパークラスで定義されたプロパティの値を変更します。メソッド、getter、または setter を使用するすべての追加の設定作業もこの時点で行うことができます。

プロパティを計算する必要がないが、新しい値を設定した前後に実行されるコードを提供する必要がある場合、willSetdidSet を使用して下さい。あなたが提供するコードは、いつでもイニシャライザの外側で値が変更した時に実行されます。例えば、以下のクラスはその三角形の辺の長さが常にその正方形の一辺の長さと同じであることを保証します。


  1. class TriangleAndSquare {
  2. var triangle: EquilateralTriangle {
  3. willSet {
  4. square.sideLength = newValue.sideLength
  5. }
  6. }
  7. var square: Square {
  8. willSet {
  9. triangle.sideLength = newValue.sideLength
  10. }
  11. }
  12. init(size: Double, name: String) {
  13. square = Square(sideLength: size, name: name)
  14. triangle = EquilateralTriangle(sideLength: size, name: name)
  15. }
  16. }
  17. var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
  18. print(triangleAndSquare.square.sideLength)
  19. // Prints "10.0"
  20. print(triangleAndSquare.triangle.sideLength)
  21. // Prints "10.0"
  22. triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
  23. print(triangleAndSquare.triangle.sideLength)
  24. // Prints "50.0"


optional の値を操作する時は、? をメソッド、プロパティ、およびサブスクリプトのような演算子の前に書くことが出来ます。もし ? の前の値が nil の時は、? の後のすべては無視され、式全体の値は nil になります。それ以外の場合は、optional の値は開封され、? の後のすべては開封された値に作用します。両方の場合とも、式全体の値は optional の値になります。


  1. let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
  2. let sideLength = optionalSquare?.sideLength


列挙型と構造体


列挙型を作成するためには enum を使用します。クラスや他のすべての名前付きの型と同じように、列挙型は、それらと関連するメソッドを持つことができます。


  1. enum Rank: Int {
  2. case ace = 1
  3. case two, three, four, five, six, seven, eight, nine, ten
  4. case jack, queen, king
  5. func simpleDescription() -> String {
  6. switch self {
  7. case .ace:
  8. return "ace"
  9. case .jack:
  10. return "jack"
  11. case .queen:
  12. return "queen"
  13. case .king:
  14. return "king"
  15. default:
  16. return String(self.rawValue)
  17. }
  18. }
  19. }
  20. let ace = Rank.Ace
  21. let  aceRawValue = ace.rawValue


実験: それらの生の値を比較することにより、2つの Rank 値を比較する関数を記述してみましょう。


デフォルトでは、Swift は生の値がゼロで開始し、1 ずつ増分しますが、明示的に値を指定することで、この動作を変更することができます。上記の例では、Ace は、明示的に 1 の生の値が与えられ、そして生の値の残りは、順に割り当てられます。また、列挙型の生の型として文字列や浮動小数点数も使用できます。列挙型の case の生の値にアクセスするために rawValue プロパティを使用します。


init?(rawValue:) イニシャライザを使用して、生の値から列挙型のインスタンスを作成します。生の値と一致する列挙型 case か、一致する Rank がない場合は nil を返します。


  1. if let convertedRank = Rank(rawValue: 3) {
  2. let threeDescription = convertedRank.simpleDescription()
  3. }

列挙型の case の値は、実際の値であり、それらの生の値を書き込むだけの他の方法ではありません。実際、意味のある生の値が存在しない case では、1つも提供する必要はありません。


  1. enum Suit {
  2. case spades, hearts, diamonds, clubs
  3. func simpleDescription() -> String {
  4. switch self {
  5. case .spades:
  6. return "spades"
  7. case .hearts:
  8. return "hearts"
  9. case .diamonds:
  10. return "diamonds"
  11. case .clubs:
  12. return "clubs"
  13. }
  14. }
  15. }
  16. let hearts = Suit.hearts
  17. let heartsDescription = hearts.simpleDescription()


実験: Suit に、スペードとクラブには"black"を返し、ハートとダイヤモンドには"red"を返す color() のメソッドを追加してみましょう。


上記の例で、列挙型の hearts の case が参照されている二つの方法に注目してください。hearts 定数に値を代入すると、その定数は指定された明示的な型を持っていないため、列挙型の case Suit.hearts は、そのフルネームで参照されます。switch の内部では、self の値はすでに suit であることが知られているので、列挙型の case は、省略形の .hearts によって参照されます。値の型が既に知られている時はいつでも省略形を使用できます。


列挙型に生の値がある場合、それらの値は宣言の一部として決定されます。つまり、特定の列挙型 case のすべてのインスタンスが常に同じ生の値を持つことを意味します。列挙型 case の別の選択肢は、case に関連付けられた値を持つことです。これらの値は、インスタンスの作成時に決定され、列挙型 case の各インスタンスごとに異なる場合があります。関連付けられた値は、列挙型 case のインスタンスの格納されたプロパティのように動作すると考えることができます。たとえば、サーバーから日の出と日没の時刻を要求する場合を考えてみましょう。サーバーは要求された情報で応答するか、何が悪かったかの説明で応答します。


  1. enum ServerResponse {
  2. case result(String, String)
  3. case failure(String)
  4. }
  5. let success = ServerResponse.result("6:00 am", "8:09 pm")
  6. let failure = ServerResponse.failure("Out of cheese.")
  7. switch success {
  8. case let .result(sunrise, sunset):
  9. print ( "Sunrise is at \(sunrise) and sunset is at \(sunset).")
  10. case let .failure(message):
  11. print ( "Failure... \(message)")
  12. }
  13. // Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."


実験: ServerResponse および switch に第三の case を追加してみましょう。


日の出と日没の時間が、switch case に対する値に一致する一部として ServerResponse の値から抽出されることに注意してください。


struct を、構造体を作成するために使用してください。構造体はメソッドおよびイニシャライザを含めた、クラスと同じ多くの動作をサポートします。構造体とクラスの間の最も重要な違いの一つは、構造体はコードの中で渡された場合には常にコピーされますが、クラスは参照によって渡されるということです。


  1. struct Card {
  2. var rank: Rank
  3. var suit: Suit
  4. func simpleDescription() -> String {
  5. return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
  6. }
  7. }
  8. let threeOfSpades = Card(rank: .three, suit: .spades)
  9. let threeOfSpadesDescription = threeOfSpades.simpleDescription()


実験: rank と suit の各々の組み合わせの一枚のカードで、トランプの完全な一組を含む、配列を返す関数を書いてみましょう。


同時実行


async を使用して、非同期で実行される関数をマークします。

  1. func fetchUserID(from server: String) async -> Int {
  2. if server == "primary" {
  3. return 97
  4. }
  5. return 501
  6. }


非同期関数の呼び出しは、その前に await を記述してマークします。


  1. func fetchUsername(from server: String) async -> String {
  2. let userID = await fetchUserID(from: server)
  3. if userID == 501 {
  4. return "John Appleseed"
  5. }
  6. return "Guest"
  7. }


async let を使用して非同期関数を呼び出し、他の非同期コードと並行して実行できるようにします。返される値を使用する場合は、await と記述します。


  1. func connectUser(to server: String) async {
  2. async let userID = fetchUserID(from: server)
  3. async let username = fetchUsername(from: server)
  4. let greeting = await "Hello \(username), user ID \(userID)"
  5. print(greeting)
  6. }


Task を使用して、return を待たずに同期コードから非同期関数を呼び出します。

  1. Task {
  2. await connectUser(to: "primary")
  3. }
  4. // Prints "Hello Guest, user ID 97"


プロトコルと拡張機能


プロトコルを宣言するためには protocol を使用してください。


  1. protocol ExampleProtocol {
  2. var simpleDescription: String { get }
  3. mutating func adjust()
  4. }


クラス、列挙型、及び構造体は、すべてプロトコルを採用することができます。


  1. class SimpleClass: ExampleProtocol {
  2. var simpleDescription: String = "A very simple class."
  3. var anotherProperty: Int = 69105
  4. func adjust() {
  5. simpleDescription += " Now 100% adjusted."
  6. }
  7. }
  8. var a = SimpleClass()
  9. a.adjust()
  10. let aDescription = a.simpleDescription
  11. struct SimpleStructure: ExampleProtocol {
  12. var simpleDescription: String = "A simple structure"
  13. mutating func adjust() {
  14. simpleDescription += " (adjusted)"
  15. }
  16. }
  17. var b = SimpleStructure()
  18. b.adjust()
  19. let bDescription = b.simpleDescription


実験: ExampleProtocol に別の要件を追加します。SimpleClassSimpleStructure に対して、プロトコルにまだ準拠するように変更する必要があるのは何ですか?


構造体を変更するメソッドをマークするために SimpleStructure の宣言の中で mutating キーワードを使う事に注意してください。SimpleClass の宣言は、クラスのメソッドはいつでもクラスを変更できるため、mutating としてそのメソッドをマークする必要はありません。


新しいメソッドや計算されたプロパティのような、既存の型に機能を追加するのに extention を使用してください。あるいは、ライブラリやフレームワークからインポートした型にさえも、別の場所で宣言されている型にプロトコルへの準拠を追加するために extension を使用できます。


  1. extension Int: ExampleProtocol {
  2. var simpleDescription: String {
  3. return "The number \(self)"
  4. }
  5. mutating func adjust() {
  6. self += 42
  7. }
  8. }
  9. print(7.simpleDescription)
  10. // Prints "The number 7"


実験: absoluteValue プロパティを追加する Double 型の拡張機能を書いてみましょう。


異なる名前の型を持つようなプロトコル名を使用できます:例えば、異なる型を持つが、すべてが単一のプロトコルに準拠しているオブジェクトのコレクションを作成できます。型がプロトコル型の値を処理する場合、プロトコル定義の外側のメソッドは利用できません。


  1. let protocolValue: ExampleProtocol = a
  2. print(protocolValue.simpleDescription)
  3. // Prints "A very simple class. Now 100% adjusted."
  4. // print(protocolValue.anotherProperty) // Uncomment to see the error


変数 protocolValueSimpleClass の実行時の型を持っているにもかかわらず、コンパイラは ExampleProtocol の与えられた型として扱います。これは、誤ってクラスがそのプロトコルの準拠性に加えて、クラスが実装するメソッドやプロパティにアクセスできないことを意味します。


エラー処理


Error プロトコルを採用している全ての型を使用してエラーを表す事ができます。


  1. enum PrinterError: Error {
  2. case outOfPaper
  3. case noToner
  4. case onFire
  5. }


エラーをスローするため throw を使用して、エラーを投げかけることができる関数をマークするために throws を使用します。関数内でエラーをスローした場合、関数はすぐに返し、関数を呼び出したコードは、エラーを処理します。


  1. func send(job: Int, toPrinter printerName: String) throws -> String {
  2. if printerName == "Never Has Toner" {
  3. throw PrinterError.noToner
  4. }
  5. return "Job sent"
  6. }


エラーを処理するにはいくつかの方法があります。一つの方法が do-catch を使用することです。do ブロックの内部では、それの前に try を書くことによって、エラーを throw できるコードをマークします。それに別の名前を付けない限り、catch ブロックの内部では、エラーは自動的に error の名前を与えられます。


  1. do {
  2. let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
  3. print(printerResponse)
  4. } catch {
  5. print(error)
  6. }
  7. // Prints "Job sent"


実験:send(job:toPrinter:) 関数はエラーを throw するように、プリンターの名前を "Never Has Toner" に変えます。


特定のエラーを処理する複数の catch ブロックを提供できます。switch 内の case の後と同じように、catch の後にパターンを書いてください。


  1. do {
  2. let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
  3. print(printerResponse)
  4. } catch PrinterError.onFire {
  5. print("I'll just put this over here, with the rest of the fire.")
  6. } catch let printerError as PrinterError {
  7. print("Printer error: \(printerError).")
  8. } catch {
  9. print(error)
  10. }
  11. // Prints "Job sent"


実験: do ブロック内に、エラーをスローするコードを追加してみましょう。どのような種類のエラーが最初の catch ブロックで処理されるようにスローする必要がありますか?第二および第三のブロックについてはどうですか?


エラーを処理する別の方法は、try? を使用し、optional に結果を変換する事です。関数がエラーをスローする場合、特定のエラーは破棄され、結果は nil となります。それ以外の場合、結果は関数が返した値を含む optional です。


  1. let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
  2. let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")


関数が戻る直前に、関数内の他のすべてのコードの後に実行されるコードのブロックを書くために defer を使用してください。コードは関数がエラーをスローするかどうかに関係なく、実行されます。それらが異なる回数実行される必要があるにもかかわらず、隣同士に設定とクリーンアップするコードを書くために defer を使用できます。


  1. var fridgeIsOpen = false
  2. let fridgeContent = ["milk", "eggs", "leftovers"]
  3. func fridgeContains(_ food: String) -> Bool {
  4. fridgeIsOpen = true
  5. defer {
  6. fridgeIsOpen = false
  7. }
  8. let result = fridgeContent.contains(food)
  9. return result
  10. }
  11. fridgeContains("banana")
  12. print(fridgeIsOpen)
  13. // Prints "false"


汎用(ジェネリック)


汎用の関数や型を作るために < > の山括弧の中に名前を書きます。


  1. func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
  2. var result = [Item]()
  3. for _ in 0..<numberOfTimes {
  4. result.append(item)
  5. }
  6. return result
  7. }
  8. makeArray(repeating:"knock", numberOfTimes:4)


関数やメソッドの汎用の形式、ならびにクラス、列挙型、および構造体を作ることができます。


  1. // Reimplement the Swift standard library's optional type
  2. enum OptionalValue<Wrapped> {
  3. case none
  4. case some(Wrapped)
  5. }
  6. var possibleInteger: OptionalValue<Int> = .none
  7. possibleInteger = .some(100)


要件のリストを指定するのに本体の直前に where を使います: 例えば、プロトコルを実装する型を必要としたり、二つの型が同じであることを必要としたり、またはクラスが特定のスーパークラスを持っている事を必要としたりします。


  1. func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
  2. where T.Element: Equatable, T.Element == U.Element
  3. {
  4. for lhsItem in lhs {
  5. for rhsItem in rhs {
  6. if lhsItem == rhsItem {
  7. return true
  8. }
  9. }
  10. }
  11. return false
  12. }
  13. anyCommonElements([1, 2, 3], [3])


実験: いずれか二つのシーケンスに共通している要素の配列を返す関数を作るために anyCommonElements(_:_:) 関数を変更してみましょう。


<T: Equatable> と書くのは、 <T> ... where T: Equatable と書くのと同じです。


前:バージョン互換性 次:Swift の基本
















トップへ












トップへ












トップへ












トップへ
目次
Xcode の新機能

Swift について
Swift と Cocoa と Objective-C (obsolete)
Swift Blog より (obsolete)

SwiftLogo
  • Swift 5.8 全メニュー


  • Swift へようこそ

  • Swift について
  • バージョン互換性
  • Swift のツアー
  • 単純な値
    制御フロー
    関数とクロージャ
    オブジェクトとクラス
    列挙型と構造体
    プロトコルと拡張機能
    エラー処理
    汎用(ジェネリック)

  • Swift 言語のガイド

  • 言語リファレンス

  • マニュアルの変更履歴













  • トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ