LoginSignup
10

More than 5 years have passed since last update.

The Many Faces of Swift Functions(objc.io #16-3 swift 日本語訳)

Last updated at Posted at 2016-01-26

By Natasha Murashev

対象読者

Swiftでの関数(メソッド)の使い方パラメータ設定方法を学びたい方

注意点

本記事は日本語訳であり、著作権はNatasha Murashevに帰属します。
オリジナルがSwift 1.2で書かれているので、オリジナルに則しました。

本文

Objective-Cは、他のプログラミング言語に比べ、いくつかの奇妙に見える構文ですが、こつを掴めばメソッドの構文は、非常に簡単です。ざっと後戻りしてみましょう。:

+ (void)mySimpleMethod
{
    // class method
    // no parameters
    // no return values
}

- (NSString *)myMethodNameWithParameter1:(NSString *)param1 parameter2:(NSNumber *)param2
{
    // instance method
    // one parameter of type NSString pointer, one parameter of type NSNumber pointer
    // must return a value of type NSString pointer
    return @"hello, world!";
}

対照的に、Swiftの構文は、より他のプログラミング言語のように見えるので、Objective-Cより複雑で、混乱もさせ得ます。

続ける前に、Swfitのメソッドと関数の間の違いを明確にしたいです。なぜならば、この記事で両方の用語を使うからです。ここで、メソッドの定義は、AppleのSwift Programming Language Bookによると、次の通りです。

メソッドは、特定の型に関連付けされている関数です。クラス、構造体、列挙はすべて与えられた型のインスタンスを操作するための特定のタスク、機能をカプセル化するインスタンスメソッドを定義することができます。クラス、構造体、列挙型も型自体に関連付けされている型メソッドも定義できます。型メソッドは、Objective-Cのクラスメソッドに似ています。

長すぎるので読んでいない:関数はスタンドアローンで、メソッドはクラス、構造体、列挙型の中にカプセル化された関数です。

Anatomy of Swift Functions(Swift関数の解剖学)

簡単な"Hello, World!"でSwiftの関数を始めましょう:

func mySimpleFunction() {
  print("hello, world!")
}

Objective-Cとは別の他の言語でプログラムしている場合、上記の関数はとても身近に見えるでしょう。

funcキーワードは、これが関数であることを示す。
・関数名はmySimpleFunctionです。
・渡されるパラメータはありません。ー従って()は空です。
・戻り値はありません。
・関数の実行は、{}の間で行われる。
さて、もう少し複雑な関数を見てみましょう:

func myFunctionName(param1: String, param2: Int) -> String {
  return "hello, world!"
}

この関数は、String型のparam1と名付けられた1つのパラメータと、Int型のparam2と名付けられた1つのパラメータとString型の戻り値を持つ。

Calling All Functions (すべての関数呼び出し)

SwiftとObjective-Cの大きな違いの一つは、Swiftの関数が呼ばれた時にどのようにパラメータが機能するかである。Objective-Cの冗長性を愛するならば、私がそうしているように、以下のことを心に留めておいてください。Swift関数が呼び出された時、デフォルトではパラメータ名は外部公開されている部分に含まれていない。

func hello(name: String) {
  print("hello \(name)")
}

hello("Mr. Roboto")

このことは、関数に対してさらにいくつかのパラメータを追加するまで、それ程悪く思えないかもしれません。

func hello(name: String, age: Int, location: String) {
  print("Hello, \(name).I live in \(location) too. When is your \(age + 1)th birthday?" ")
}

hello("Mr. Roboto", 5, "San Francisco")

hello("Mr. Roboto", 5, "San Francisco")を読むことのみからパラメータの各々が実際何であるかを理解するのは苦労するでしょう。Swiftには、この混乱を明確にする外部パラメータ名という概念があります。

func hello(fromName name: String) {
  print("\(name) says hello to you!")
}

hello(fromName: "Mr. Roboto")

上記関数で、fromNameは関数呼び出し時に含まれる外部パラメータです。一方、nameは関数の実行の内側でそのパラメータを参照するために使われる内部パラメータです。

外部パラメータと内部パラメータの名前を同じにしたい場合、以下のように二度パラメータ名を記述する必要はありません。

func hello(name name: String) {
    print("hello \(name)")
}

hello(name: "Robot")

その代わりに、ただのショートカットとして、以下のようにパラメータ名の前に#を追加します。:

func hello(#name: String) {
  print("hello \(name")
}

hello(name: "Robot")

そして、勿論どのようにパラメータが働くかという規則はメソッドで若干異なります。

Calling on Methods (メソッドの呼び出し)

あるクラス(あるいは構造体または列挙子)でカプセル化されている時、メソッドの最初のパラメータ名は外部に提供されていない。一方、それに続くすべてのパラメータの名前は、そのメソッドが呼ばれる時に外部パラメータに含まれている。

class MyFunClass {

  func hello(name: String, age: Int, location: String) {
    print("Hello \(name).I live in \(location) too. When is your \(age + 1)th birthday?"")
  }
}

let myFunClass = MyFunClass()
myFunClass.hello("Mr. Roboto", age: 5, location: "San Francisco")

従って、ベストプラクティスは、Objective-Cのようにメソッド名に最初のパラメータ名を含めることです。


class MyFunClass {

    func helloWithName(name: String, age: Int, location: String) {
        print("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
    }

}

let myFunClass = MyFunClass()
myFunClass.helloWithName("Mr. Roboto", age: 5, location: "San Francisco")

hello関数を呼び出す代わりに、最初のパラメータがnameであるということをとてもクリアにするためにhelloWithNameにリネームしました。

いくつかの特別な理由で(私はそうするために非常に良い理由を持つお勧めします)関数の外部パラメータ名を省略する場合、外部パラメータ名に_を使用します。

class MyFunClass {

    func helloWithName(name: String, _ age: Int, _ location: String) {
        print("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
    }

}

let myFunClass = MyFunClass()
myFunClass.helloWithName("Mr. Roboto", 5, "San Francisco")

Instance Methods Are Curried Functions (インスタンスメソッドはカリー関数)

Swiftで注意するクールなことの一つは、インスタンスメソッドが正にカリー化関数であることです。

カリー化することの基本的な考えは、関数が呼ばれる前に、パラメータ値のいくつかを明示(バインド)できることを意味し、部分的に適用したりできるということです。部分関数アプリケーションは、新たな機能を与えます。

以下のようなクラスを考えます。

class MyHelloWorldClass {

  func helloWithName(name: String) -> String {
    return "hello \(name)"
  }

}

以下のようにクラスのhelloWithName関数を指す変数を作成することができます。

let helloWithNameFunc = MyHelloWorldClass.helloWithName
// MyHelloWorldClass -> (String) -> String

新しいhelloWithNameFuncMyHelloWorldClass -> (String) -> String
という型である。先ほどのクラスのインスタンスを取り込関数です。型で、そのクラスのインスタンスを取り込み、別の(ある文字列値を取り込み、ある文字列値を返すという)関数です。

実際このように先ほど関数を呼びます。

 let myHelloWorldClassInstance = MyHelloWorldClass()

 helloWithNameFunc(myHelloWorldClassInstance)("Mr. Roboto")
 // hello, Mr. Roboto

Init: A Special Note (初期化:特筆すべきこと)

特別なinitメソッドが、クラス、構造体、enumが初期化される時に呼ばれます。Swiftにおいて、他のメソッド同様初期化パラメータを定義できます。

class Person {

  init(name: String) {
    // your init  implementation
  }
}

Person(name: "Mr. Roboto")

クラスをインスタンス化する時に他の方法と異なり init メソッドの最初のパラメータ名が外部から要求されていることに注意してください。

初期化をより読みやすくするためのベストプラクティスは、ほとんどのケースにおいて、異なる外部パラメータ名を加えることです。このケースだとfromNameです。

class Person {

  init(fromName name: String) {
    // your init implementation
  }

}

Person(fromName: "Mr. Roboto")

そして、勿論他のメソッドのように、初期化メソッドで外部パラメータを省略したいならば_を付け加えることができる。私は、Swift Programming Language Book出典の、初期化例の読みやすさとパワーが好きです。

struct Celsius {
  var temperatureInCelsius: Double
  init(fromFahrenheit fahrenheit: Double) {
    temperatureInCelsius = (fahrenheit - 32.0) / 1.8
  }
  init(fromKelvin kelvin: Double) {
    temperratureInCelsius = kelvin - 273.15
  }
  init(_ celsius: Double) {
    temperatureInCelsius = celsius
  }
}

let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0

let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0

let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius is 37.0

クラス/列挙型/構造体を初期化することを抽象化したい場合は、外部パラメータをスキップすることも役立ちます。私はデビッド・オーウェンのJSON-SWIFTライブラリでこれを使用することを好みます。:

public struct JSValue: Equatable {

  // ... truncated code

  /// Initializes a new `JSValue` with a `JSArrayType` value.
  public init(_ value: JSArrayType) {
    self.value = JSBackingValue.JSArray(value)
  }

  /// Initializes a new `JSValue` with a `JSObjectType` value.
  public init(_ value: JSObjectType) {
    self.value = JSBackingValue.JSObject(value)
  }

  /// Initializes a new `JSValue` with a `JSStringType` value.
  public init(_ value: JSStringType) {
    self.value = JSBackingValue.JSString(value)
  }

  /// Initializes a new `JSValue` with a `JSNumberType` value.
  public init(_ value: JSNumberType) {
    self.value = JSBackingValue.JSNumber(value)
  }

  /// Initializes a new `JSValue` with a `JSBoolType` value.
  public init(_ value: JSBoolType) {
    self.value = JSBackingValue.JSBool(value)
  }

  /// Initializes a new `JSValue` with an `Error` value.
  init(_ error: Error) {
    self.value = JSBackingValue.Invalid(error)
  }

  /// Initializes a new `JSValue` with a `JSBackingValue` value.
  init(_ value: JSBackingValue) {
    self.value = value
  }
}

Fancy Parameters

Objective-Cと比較すると、Swiftには渡すことができるパラメータの型に対しての追加オプションがたくさんあります。幾つかの例を記します。

Optional Parameter Types (Optional型のパラメータ)

Swiftにおけるオプショナル型の新しい概念があります。

オプショナルは、"値があり、それはxに等しい"あるは"値が全くないこと"です。オプショナルはObjective-Cのポインターでnilを使うことに似ている。しかし、クラスだけでなく任意の型で動作する。オプショナルはObjective-Cのnilポインターより安全で、より表現力がある。そして強力なSwiftの多く特徴のうちの心臓部です。

パラメータの型がオプショナルである(nilになりうる)ことを示すためには、?マークを型宣言のあとに追加するだけです。

func myFunctionWithOptionalType(parameter: String?) {
  // function execution
}

myFunctionWithOptionalType("someString")
myFUnctionWithOptionalType(nil)

オプショナルで作業するとき、アンラップすることを忘れないでください!

func myFunctionWithOptionalType(optionalParameter: String?) {
  if let unwrappedOptional = optionalParameter {
    print("The optional has a value! It's \(unwrappedOptional)")
  } else {
    print("The optional is nil!")
  }
}

myFunctionWithOptionalType("someString")
myFUnctionWithOptionalType(nil)

Objective-Cからの移行者は、オプショナルでの作業に慣れるのに間違いなく幾分時間がかかります!

Parameters with Default Values(デフォルト値を持つパラメータ)

func hello(name: Stirng = "you") {
  print("hello, \(name)")
}

hello(name: "Mr. Roboto")
// hello, Mr. Roboto

hello()
// hello, you

デフォルト値を持つパラメータは、外部パラメータを自動的に持つことに注意してください。

関数が呼び出される時、デフォルト値のパラメータをスキップできるので、関数のパラメータリストの末尾にデフォルト値を持つすべてのパラメータを配置することがベストプラクティスです。Swift Language Bookからノートは次の通りです。

関数のパラメータ一覧の末尾にデフォルト値をもつパラメータを配置します。これは、デフォルト値を持たないパラメータと同じ順序で使用することを保証し、それぞれの場合に呼び出されている同じ関数ことを明確にする。

私は、デフォルトパラメータの大ファンです。なぜならば、それによりコードを変更することが容易で、下位互換になるからです。あなたは、一度特定のユースケースで二つのパラメータを用いて開始するでしょう。そのような機能としてカスタムのUITableViewCellを設定して別のユースケースを起動した場合、(セルのラベルに異なるテキスト色のような)別のパラメータを必要とすることが生じる別のケースであるならば、デフォルト値付きのパラメータを追加するでしょう。- この関数が呼び出される他のすべての場所は優れている。そして、そのパラメータを必要とするコードの新しい部分において単にデフォルト以外の値を渡すことができます。

Variadic Parameters(可変個引数パラメータ)

可変個引数のパラメータは、単純な要素の配列を渡すより読みやすいものになっています。実際、以下の例で内部パラメータ名を見ると、それが[String]型(stringの配列)であることが分かる。

func hellowWithName(names: String...) {
  for name in names {
    print("Hello, \(name)")
  }
}

// 2 names
helloWithNames("Mr. Robot", "Mr. Potato")
// Hello, Mr. Robot
// Hello, Mr. Potato

// 4 names
helloWithNames("Batman", "Superman", "Wonder Woman", "Catwoman")
// Hello, Batman
// Hello, Superman
// Hello, Wonder Woman
// Hello, Catwoman

ここでの理解は、空の配列を渡すことが可能なように0値を渡すことが可能であることを覚えておくことです。それ故必要に応じで、空配列をチェックすることを忘れないでください。

func helloWithNames(names: String...) {
  if names.count > 0 {
    print("Hello, \(name")
  } else {
    print("Nobody here!")
  }
}

helloWithNames()
// Nobody here!

可変個のパラメータについてのもう一つの注意:可変引数パラメータは、関数のパラメータリストの最後のパラメーターでなければなりません!

Inout Parameters

inoutパラメータを使用することにより外部変数を操作できます。(参照渡しとして知られています)。

var name1 = "Mr. Potato"
var name2 = "Mr. Roboto"

func nameSwap(inout name1: String, inout name2: String) {
  let oldName1 = name1
  name1 = name2
  name2 = oldName1
}

nameSwap(&name1, &name2)

name1
// Mr. Roboto

name2
// Mr. Potato

これは、エラーシナリオを処理するためのObjective-Cの中で非常に一般的なパターンです。以下のNSJSONSerializationは、ほんの一例です。

- (void)parseJSONData:(NSData *)jsonData
{
  NSError *error = nil;
  id jsonResult = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
  if (!jsonResult) {
    NSLog(@"ERROR: %@", error.description);
  }
}

Swiftはとても新しいので、まだエラー処理に対する明確な規則がありません。しかし、inoutパラメータの先に多くのオプションが、間違いなくあります。Swiftにおけるエラーハンドリングに関するデビッド・オーウェンの最近のブログ記事を見てみましょう。このトピックに関する詳細は、また、Swiftにおける関数型プログラミングでカバーする必要があります。

Generic Parameter Types (ジェネリクスパラメータ型)

私は、この記事でジェネリクスの多くを取り上げない。しかし、単純な例、両方のパラメータが同じ型であることを確保する一方、いかに異なる型のパラメータを受け付ける関数を作ることができるか、ここに示します。・

func valueSwap<T>(inout value1: T, inout value2: T) {
  let oldValue1 = value1
  value1 = value2
  value2 = oldValue1
}

var name1 = "Mr. Potato"
var name2 = "Mr. Roboto"

valueSwap(&name1, &name2)

name1 // Mr. Roboto
name2 // Mr. Potato

var number1 = 2
var number2 = 5

valueSwap(&number1, &number2)

number1 // 5
number2 // 2

ジェネリクスに関するより多くの情報はSwiftプログラミング言語の本のgenericsのセクションを見ることをお勧めします。

Variable Parameters(変数パラメータ)

デフォルトでは、関数に渡されるパラメータは定数であり、それらは関数のスコープ内で操作することはできません。あなたがその動作を変更したい場合は、パラメータのvarキーワードを使用します。

var name = "Mr. Roboto"

func appendNumbersToName(var name: String, #maxNumber: Int) -> String {
  for i in 0..<maxNumber {
    name += String(i + 1)
  }
  return name
}

appendNumbersToName(name, maxNumber: 5)
// Mr. Roboto12345

name
// Mr. Roboto

これはINOUTパラメータとは異なることに注意してください - 可変パラメータは、外部渡された変数を変更しない!

Functions as Parameters(パラメータとしての関数)

Swiftでは、変数のように関数を渡すことができる。例えば、関数は、パラメータとして渡される別の関数を持つことができる。

func luckyNumberForName(name: String, #lotteryHander: (String, Int) -> String) -> String {
  let luckyNumber = Int(arc4randam() % 100)
  return lotteryHander(name, luckyNumber)
}

func defalutLotteryHandler(name: String, luckyNumber: Int) -> String {
  return "\(name), your lucky number is \(luckyNumber)"
}

luckyNumberForName("Mr. Roboto", lotteryHander: defalutLotteryHandler)
// Mr. Roboto, your lucky numbあer is 38

この場合には、defalultLotteryHandlerのみ関数参照が渡されることに注意してください。その関数は、受け取った関数によって決定し、後で実行される。

インスタンスメソッドも同様の方法で渡すことができます。

func luckyNubmerForName(name: String, #lotteryHandler: (String, Int) -> String {
  let luckyNumber = Int(arc4randam() % 100)
  return lotteryHandler(name, luckyNumber)
}

class FunLottery {

  func defaultLotteryHandler(name: String , luckyNumber: Int) -> String {
    return "\(name), your lucky number is \(luckyNumber)"
  }
}

let funLottery = FunLottery()
luckyNumberForName("Mr. Roboto", lotteryHandler: funLottery.defaultLotteryHandler)
// Mr. Roboto, your lucky number is 38

関数定義をもう少し読みやすくするには、関数をタイプエイリアスすることを考慮すると良いです。(Objective-Cでのtypedefと同じように)

typealias lotteryOutputHandler = (String, Int) -> String

func luckyNumberForName(name: String, #lotteryHandler: lotteryOutputHandler) -> String {
  let luckyNumber = Int(arc4randam() % 100)
  return lotteryHandler(name, luckyNumber)
}

また、パラメータの型として名前を指定せず関数を適用することができる。(Objective-Cのブロックと同じように)

func luckyNumberForName(name: String, #lotteryHandler: (String, Int) -> String) -> String {
  let luckyNumber = Int(arc4randam() % 100)
  return lotteryHandler(name, luckyNumber)
}

luckyNumberForName("Mr. Roboto", lotteryHandler: {name, number in
  return "\(name)'s' lucky number is \(number)"
})
// Mr. Roboto's lucky number is 74

Objective-Cで、パラメータとしてブロックを使うことは、非同期オペレーションを実行するメソッドで完了やエラーハンドラで一般的です。このことは、Swiftでも同様一般的なパターンであり続けるべきです。

Access Controls

Swiftには、アクセスを制御する3つレベルがある。

・Publicアクセスは、エンティティがその定義モジュールからどのようなソースファイルで使われることを
可能にする。そしてまた定義しているモジュールをインポートして他のモジュールからも同様に使用することができます。
フレームワークへの公開インターフェイスを指定するときは、一般的にpublicアクセスを使用する。
・Internalアクセスは、エンティティがそれらを定義するモジュールからどのようなソースファイルで使われることを可能にする。しかしそのモジュールの外のどのようなソースファイルからは不可能である。
・Privateアクセスは、エンティティに対して定義しているソースファイル自身での使用に限る。関数の特定の部分の詳細を隠蔽したい時にprivateアクセスを使う。

デフォルトで全ての関数と変数は、internalである。ーそれを変更したい場合はすべての単一のメソッドと変数の前にprivatepublicキーワードを使用する必要がある。

public func myPublicFunc() {

}

func myInternalFunc() {

}

private func myPrivateFunc() {

}

private func myOtherPrivateFunc() {

}

RubyからSwiftに辿り着いているので、privateな関数をクラスの下部にランドマークで区切って実装することを好む。

class MyFunClass {
  func myInternalFunc() {

  }

  // MARK: Private Helper method

  private func myPrivateFunc() {

  }

  private func myOtherPrivateFunc() {

  }
}

うまくいけば、Swiftの将来のリリースで、その下のすべてのメソッドがpriveにすることを示すprivateキーワードを使用するためのオプションを組入れるでしょう。他のプログラミング言語でアクセスコントロールが作用するのと同じように。

Fancy Return Types(色々な戻り値の型)

Swiftでは、関数の戻り値の方と値ははObjective-Cで慣れている形式よりも少し複雑でありうる。

Optional Return Types

関数がnil値を返す可能性がある場合、オプショナル型の戻り値を指定する必要がある。

func myFuncWithOptionalReturnType() -> String? {
  let someNumber = arc4random() % 100
  if someNumber > 50 {
    return "someString"
  } else {
    return nil
  }
}

myFuncWithOptionalReturnType()

そしてもちろん、そのオプショナル形式の戻り値を使用する時はアンラップすることを忘れないでください。(以下のように)

let optionalString = myFuncWithOptonalReturnType()

if let someString = optionalString {
    print("The function returned a value: \(someString)")
} else {
    print("The function returned nil")
}

私がオプショナルの説明で見た最高のものは、@Kronusdarkのツイートです。

私は最終的にSwift言語でオプショナルは、シュレーディンガーの猫のようなものです!それを使用する前に、それが有効かどうか確認する必要がある。

Multiple Return values(複数の戻り値)

Swiftの最も魅力的な機能の1つは、関数が複数の戻り値を持てることです:

func findRangeFromNumbers(numbers: Int...) -> (min: Int, max: Int) {

  var min = numbers[0]
  var max = numbers[0]

  for number in numbers {
    if number > max {
      max = number
    }

    if number < min {
      min = number
    }
  }
  return (min, max)
}

findRangeFromNumbers(1, 234, 555, 345, 423)
// (1, 555))

複数の戻り値は、タプル(グループされた値のとてもシンプルなデータ構造を持つデータ)で値を返されているということが分かる。そのタプルから複数の戻り値を使うには、二つの方法がある。

let range = findRangeFromNumbers(1, 234, 555, 345, 423)
print("From numbers: 1, 234, 555, 345, 423. The min is \(range.min). The max is \(range.max).")
// From numbers: 1, 234, 555, 345, 423. The min is 1. The max is 555.

let (min, max) = findRangeFromNumbers(236, 8, 38, 937, 328)
print("From numbers: 236, 8, 38, 937, 328. The min is \(min). The max is \(max)")
// From numbers: 236, 8, 38, 937, 328. The min is 8. The max is 937

Multiple Return Values and Optionals(複数の戻り値とオプショナル)

複数の戻り値においてトリッキーな部分は、戻り値がオプショナルで有り得る時です。しかし、オプショナルの複数の戻り値を処理する2つの方法があります。

上の関数の例において、ロジックに欠陥がある。ー値が渡されない可能性があり、それが発生するとプログラムは、実際クラッシュするでしょう。もし、何も値が渡されていないことがあるならば、戻り値全体をオプショナルにすべきです。:

func findRangeFromNumbers(numbers: Int...) -> (min: Int, max: Int)? {

    if numbers.count > 0 {

        var min = numbers[0]
        var max = numbers[0]

        for number in numbers {
            if number > max {
                max = number
            }

            if number < min {
                min = number
            }
        }

        return (min, max)
    } else {
        return nil
    }
}

if let range = findRangeFromNumbers() {
    print("Max: \(range.max). Min: \(range.min)")
} else {
    print("No numbers!")
}
// No numbers!

他の場合は、全体ではなくタプル其々の戻り値をにオプショナルにするということが分かるでしょう。

func componentsFromUrlString(urlString: String) -> (host: String?, path: String?) {
  let url = NSURL(string: urlString)
  return (url.host, url.path)
}

あるタプルの値がオプショナルでありうることを定義した場合、少しアンラップしずらくなります。なぜならば、オプショナル値の単一の組み合わせを考慮する必要があるためです。

let urlComponent = componentsFromUrlString("http://name.com/12345;param?foo=1&baa=2#fragment")

switch (urlComponents.host, urlComponents.path) {
  case let (.Some(host), .Some(path)):
    print("This url consists of host \(host) and path \(path)" )
  case let (.Some(host), .None):
    print("This url only has a host \(host)")
  case let (.None, Some(path)):
    print("This url only has path \(path). Make sure to add a host!")
  case let (.None, .None):
    print("This is not a url!")
}
// This url consists of host name.com and path /12345

並みのObjective-Cの方法ですることでない!ということが分かる。

Return a Function(関数型の戻り値)

swiftで任意の関数は、関数を返すこともできる。

func myFuncThatReturnAFunc() -> (Int) -> String {
  return { number in
    return "The lucky number is \(number)"
  }
  let returnedFunction = myFuncThatReturnAFunc()

  returnedFunction(5) // The lucky number is 5
}

これを読みやすくするために、もちろん戻り値の型関数のタイプエイリアスを使えます。

typealias returnFuntionType = (Int) -> String
func myFuncThatReturnsAFunc() -> returnFunctionType {
  return { number in
    return "The lucky number is \(number)"
  }
}

let returnedFunction = myFuncThatReturnsAFunc()

returnedFunction(5) // The lucky number is 5

Nested Functions(関数のネスト)

そして、この関数の記事に飽きていないのであれば、Swiftで関数の中に関数を持てることを知るのは常に良いことです。

func myFunctionWithNumber(someNumber: Int) {

    func increment(var someNumber: Int) -> Int {
        return someNumber + 10
    }

    let incrementedNumber = increment(someNumber)
    print("The incremented number is \(incrementedNumber)")
}

myFunctionWithNumber(5)
// The incremented number is 15

@end(結び)

Swift関数は、多くのオプションと機能を持つ。Swiftで書き始めたら、偉大な機能は、偉大な責務からもたらされているということを覚えておいてください。巧みさよりも読みやすくするための最適化!

Swiftのベストプラクティスはまだ十分に確立していない。そして、その言語は依然として絶えず変化しているので、あなたのコードは友人や同僚にレビューを受けます。私はSwiftを一度も見たことがない人が前に時々最も私のSwiftのコードについて教えていることを発見しました。

swiftを楽しんでください!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10