Skip to content

Instantly share code, notes, and snippets.

@KentarouKanno
Last active February 8, 2016 14:46
Show Gist options
  • Save KentarouKanno/53a7b64baf97c7d46657 to your computer and use it in GitHub Desktop.
Save KentarouKanno/53a7b64baf97c7d46657 to your computer and use it in GitHub Desktop.
Function

Function

★ インスタンスメソッド

class FuncClass {
    func method() {
        print("Instance method!")
    }
    
    var method1: FuncClass -> () -> () = method
}

let obj = FuncClass()
obj.method()
//=> Instance method!

var val = obj.method1
val.dynamicType
//=> (FuncClass -> () -> ()).Type

val(obj)()
//=> Instance method!

★ クラスメソッド

class FuncClass {
    class func method() {
        print("Class method!")
    }
}

FuncClass.method()
//=> Class method!

★ タイプメソッド

class FuncClass {
    static func method1() {
        print("Type method")
    }
}

FuncClass.method()

★ アクセスコントロール Private

private func privateFunction() {
    print("privateFunction")
}

★ アクセスコントロール internal

internal func internalFunction() {
    print("internalFunction")
}

★ アクセスコントロール public

public func publicFunction() {
    print("publicFunction")
}

★ 引数なし、戻り値なし

func method() {
    print("Call Method!")
}

// 呼び出し1
method()
//=> Call Method!

// 呼び出し2
performSelector("method")


// 以下の記述でも同じ意味
func method(_: Void) { print("Call Method!") }
func method() -> () { print("Call Method!") }
func method() -> Void { print("Call Method!") }

// --------------------

func method() -> () {
    print("Call Method!")
    // 空のタプルを返す
    return ()
}

★ 引数1つ(Int型)、戻り値なし(外部引数名なし)

func method(value: Int) {
    print("value = \(value)")
}

// 呼び出し
method(3)
//=> value = 3

★ 引数がOptional型の場合 (Optional Parameter Type)

func method(value: Int?) {
    print("value = \(value)")
}

method(5)
//=> value = Optional(5)

method(nil)
//=> value = nil

★ 引数1つ(Int型)、戻り値なし(外部引数名あり)

func method(value value: Int) {
    print("value = \(value)")
}

// 呼び出し
method(value: 3)
//=> value = 3

★ 引数2つ: Int型、戻り値なし
1つ目の変数は外部引数名なし、2つ目以降はあり ※Default

func method(value1: Int, value2: Int) {
    print("Total = \(value1 + value2)")
}

// 呼び出し
method(2, value2: 3)
//=> Total = 5

★ 引数2つ: Int型、戻り値なし (外部引数名なし)
明示的に外部引数名をなしにする場合『_』ワールドカードを使用する

func method(value1: Int,_ value2: Int) {
    print("Total = \(value1 + value2)")
}

// 呼び出し
method(2, 3)
//=> Total = 5

★ 引数2つ: Int型、戻り値: String

func method(value1: Int, value2: Int) -> String {
    return "Total = \(value1 + value2)"
}

// 呼び出し
let total = method(2, value2: 3)
//=> total =  "Total = 5"

// ----------------------

// 引数をタプルで置き換える

var varTuple: (Int, value2: Int) = (2, 3)
var total = method(varTuple as (Int, value2: Int))
//=> "Total = 5"
// varで宣言した場合は変数宣言時に型指定してもキャストが必要

// 上記と同じ
typealias TupleType = (Int, value2: Int)
var varTuple = (2, 3)
var total = method(varTuple as TupleType)

// 型推論
let letTuple = (2, value2: 3)

// 型指定
let letTuple: (Int, value2: Int) = (2, 3)
var total = method(letTuple)
//=> "Total = 5"
// letで宣言した場合は変数宣言時に型指定するとキャストは不要

★ 戻り値がOptional型の場合

func method(str: String) -> Int? {
    return Int(str)
}

var result = method("5")
//=> Optional(5)

var result = method("abc")
//=> nil

★ タプルを使用して複数の戻り値を返す

func method(value1: Int, _ value2: Int) -> (Int, Int, Int) {
    let v1 = value1 * 2
    let v2 = value2 * 2
    return (v1, v2, v1 + v2)
}

// 呼び出し
let returnValue = method(2, 3)
//=> returnValue =  (4, 6, 10)

returnValue.0
//=> 4

returnValue.1
//=> 6

returnValue.2
//=> 10

// -------------------

// 戻り値のタプルに名前を付ける

func method(value1: Int, _ value2: Int) -> (val1: Int, val2: Int, total: Int) {
    let v1 = value1 * 2
    let v2 = value2 * 2
    return (v1, v2, v1 + v2)
}

let returnValue = method(2, 3)
//=> returnValue =  (4, 6, 10)

returnValue.val1
returnValue.val2
returnValue.total

★ 変数の既定値を設定する(型名の後ろに = 『既定値』で設定する)

func method(value1: Int = 2, value2: Int = 3) -> String {
    return "Total = \(value1 + value2)"
}

// 呼び出し(既定値を設定している場合その引数は省略できる)
let total = method()
//=> total =  "Total = 5"

★ 引数を変数として扱う

// 関数の引数は通常letとして定義しているので変更はできない
func method(value: Int) {
    value = 5 // エラー
}

func method(var value: Int) {
    value = 5
    print("value = \(value)")
}

// 呼び出し
method(3)
//=> value = 5

★ 関数を変数に代入する

func method() {
    print("Call Method!")
}

// 型推論の場合
var methodObj = method

// 型指定の場合 ※引数がなく戻り値もない型
var methodObj: (() -> ()) = method

methodObj.dynamicType
//=> (() -> ()).Type

// 実行する
methodObj()
//=> "Call Method!"

// ------------

func addTwoInts(a: Int, b: Int) -> Int {
    return a + b
}

func multiplyTwoInts(a: Int, b: Int) -> Int {
    return a * b
}

// 『(Int, Int) -> Int』 型の変数 function
var function: (Int, Int) -> Int

// 同じ型なので代入できる
function = addTwoInts
function = multiplyTwoInts

var multiValue = function(2, 3)
//=> 6

★ 変数のポインタを渡す(inout引数)

func mySwap(inout a: Int, inout _ b: Int) {
    let tmp = a; a = b; b = tmp
}

var a = 10
var b = 5
mySwap(&a, &b)

//=> a = 5
//=> b = 10

★ 引数に可変長引数をとる関数

func method(value: Int...) {
    // 引数は配列として取得される
    print("value = \(value)")
}

// 呼び出し
method(1, 2, 3)
//=> value = [1, 2, 3]

★ 関数を引数にする関数

func funcMethod(value: Int) -> Int {
    return value * 2
}

func method(function: (Int -> Int),value: Int) -> Int {
    return function(value)
}

var returnValue = method(funcMethod, value: 5)
//=> returnValue = 10


// 上記の関数にDefault値を設定した場合
func method(function: (Int -> Int) = { value -> Int in return value * 5 },value: Int) -> Int {
    return function(value)
}

var returnValue = method(value: 5)
//=> returnValue = 25

// -------------------------

// クロージャー1

var funcMethod: (Int -> Int) =  { (value: Int) in return value * 2 }
// var funcMethod =  { $0 * 2 }  型推論
// funcMethod.dynamicType -> (Int -> Int).Type

func method(function: (Int -> Int),value: Int) -> Int {
    return function(value)
}

var returnValue = method(funcMethod, value: 5)
//=> returnValue = 10

// クロージャー2

func method(function: (Int -> Int),value: Int) -> Int {
    return function(value)
}

var returnValue = method({ (value: Int) in return value * 2 }, value: 5)
//=> returnValue = 10

★ 関数を戻り値にとる関数

func add(a: Int, b: Int) -> Int {
    return a + b
}

func multi(a: Int, b: Int) -> Int {
    return a * b
}

func method(isAdd: Bool) -> (Int, Int) -> Int {
    
    return isAdd ? add : multi
}

var function: (Int, Int) -> Int = method(false)

var value = function(2,5)
//=> value = 10

★ ネストした関数(nested Function)

func method(isAdd: Bool) -> (Int, Int) -> Int {
    
    func add(a: Int, b: Int) -> Int {
        return a + b
    }
    
    func multi(a: Int, b: Int) -> Int {
        return a * b
    }
    
    return isAdd ? add : multi
}

method.dynamicType
//=> (Bool -> (Int, Int) -> Int).Type

var function: (Int, Int) -> Int = method(false)

var value = function(2,5)
//=> value = 10

// 以下の記述でも同じ
var value = method(false)(2, 5)
//=> value = 10k

// -----------------

func add(a: Int) -> (Int -> Int) {
    // クロージャーを返す
    return { (b: Int) -> Int in return a + b }
}

// 上記を省略した記述
func add(a: Int) -> Int -> Int { return { a + $0 }}

// 呼び出し方1
let function = add(2)
let sum = function(3)
//=> sum = 5

function.dynamicType
//=> (Int -> Int).Type

// 呼び出し方2
let sum = add(2)(3)
//=> sum = 5

// -----------------

// 変数に代入
var addFunction = add
addFunction.dynamicType
//=> (Int -> Int -> Int).Type

★ カリー化された関数

func add(a: Int)(_ b: Int) -> Int {
  return a + b
}

var sum = add(2)(3)
//=> sum = 5

// 以下のクロージャーと同じ動きです
func add(a: Int) -> (Int -> Int) {
    return { (b: Int) -> Int in return a + b }
}

var sum = add(2)(3)
//=> sum = 5

// ----------------------

// 以下の4つのコードはいずれも文字列配列を指定の文字で結合した文字を返すコード
// ["A", "B", "C"] => "A-B-C"

// 関数として定義
func appendSeparatorToStrings(strings: [String],_ separator: String) -> String {
    return strings.joinWithSeparator(separator)
}

appendSeparatorToStrings(["A", "B", "C"], "-")
//=> "A-B-C"

// -------------------

// ネスト関数として定義
func appendSeparatorA(separator: String) -> ([String] -> String) {
    func appendStrings(strings: [String]) -> String {
        return strings.joinWithSeparator(separator)
    }
    return appendStrings
}

appendSeparatorA("-")(["A", "B", "C"])
//=> "A-B-C"

// -------------------

// ネスト関数として定義(クロージャー)
func appendSeparatorC(separator: String) -> ([String] -> String) {
    return { $0.joinWithSeparator(separator) }
}

appendSeparatorC("-")(["A", "B", "C"])
//=> "A-B-C"

// -------------------

// カリー化記法で定義
func appendSeparatorB(separator: String)(_ strings: [String]) -> String {
    return strings.joinWithSeparator(separator)
}

appendSeparatorB("-")(["A", "B", "C"])
//=> "A-B-C"

appendSeparatorB.dynamicType
//=> (String -> Array<String> -> String).Type

// -------------------

// カリー化の利点
// 関数の処理を分けられ、簡潔に書ける

let appendNewlineToStrings = appendSeparatorB("-")
appendNewlineToStrings([ "A", "B", "C" ])
//=> "A-B-C"

let appendSpaceToStrings = appendSeparatorB(" ")
appendSpaceToStrings([ "D", "E", "F" ])
//=> "D E F"

// -------------------
// カリー化いろいろ

func method1(a: Int, b: Int, c: Int) -> Int {
    return (a + b) * c
}

method1.dynamicType
//=> ((Int, Int, Int) -> Int).Type

var a1 = method1(1, b: 2, c: 3)
//=> 9

// -------------------

func method2(a: Int)(b: Int, c: Int) -> Int {
    return (a + b) * c
}

method2.dynamicType
//=> (Int -> (Int, Int) -> Int).Type

var b1 = method2(1)
var b2 = b1(b: 2, c: 3)
//=> 9

var b3 = method2(1)(b: 2, c: 3)

// -------------------

func method3(a: Int, b: Int)(c: Int) -> Int {
    return (a + b) * c
}

method3.dynamicType
//=> ((Int, Int) -> Int -> Int).Type

var c1 = method3(1, b: 2)
var c2 = c1(c: 3)
//=> 9

var c3 = method3(1, b: 2)(c: 3)

// -------------------

func method4(a: Int)(b: Int)(c: Int) -> Int {
    return (a + b) * c
}

method4.dynamicType
//=> (Int -> Int -> Int -> Int).Type

var d1 = method4(1)
var d2 = d1(b: 2)
var d3 = d2(c: 3)
//=> 9

var d4 = method4(1)(b: 2)(c: 3)

// -------------------

func method5(a: Int, b: Int, c: Int)() -> Int {
    return (a + b) * c
}

method5.dynamicType
//=> ((Int, Int, Int) -> () -> Int).Type

var e1 = method5(1, b: 2, c: 3)
var e2 = e1()
//=> 9

// ---------------

func method6(a: Int) -> Int -> Int -> Int {
    func method7(b: Int) -> Int -> Int {
        func method8(c: Int) -> Int {
            return (a + b) * c
        }
        return method8
    }
    return method7
}

func method6(a: Int) -> Int -> Int -> Int {
    return { (b: Int) -> Int -> Int in
        return { (c: Int) -> Int in
            return (a + b) * c
        }
    }
}

method6(1)(2)(3)
//=> 9

★ 無名関数 クロージャー

// 構文 { (parameters) -> return type in statements }

// 『() -> ()』型の関数
var function: () -> () = { print("Call Method!") }

// 実行
function()

do {
    // 無名関数に『()』を付けて直ぐに実行
    { print("Call Method!")}()
}

// ---------------

var function: Int -> Int = { (a: Int) -> Int in return a * 2 }
// 省略形(Shorthand Argument Names)
var function: Int -> Int = { $0 * 2 }

// 実行
var  value = function(3)
//=> 6

// 無名関数に『()』を付けて直ぐに実行
var value = { (a: Int) -> Int in return a * 2 }(3)
//=> 6

// ---------------

// ----- Capturing Values(キャプチャ値)-----
var function: () -> () -> Int = { var x = 0; return { x += 1; return x } }

// 上記を複数行で記述
var function: () -> () -> Int = {
    var x = 0
    
    return {
        x += 1
        return x
    }
}

// 関数を実行する度に1増えた値を返す関数
var f = function()
f() //=> 1
f() //=> 2
f() //=> 3

// ------------------

func add(val1: Int, _  val2: Int, _ closure: (Int, Int) -> Int) -> Int {
    return closure(val1, val2)
}

var value = add(2, 3, { (a: Int, b: Int) -> Int in return a + b })
//=> 5

// ----- Trailing Closures(後置記法)-----
// 引数の最後がクロージャーの場合は『()』の外にクロージャーを記述できる
var value = add(2, 3) { (a: Int, b: Int) -> Int in return a + b }

// 上記を省略した場合
var value = add(2, 3, { $0 + $1 })
var value = add(2, 3) { $0 + $1 }

// -----  Operator Functions(演算子関数)-----
// 『+』は public func +(lhs: Int, rhs: Int) -> Int のように定義されているのでクロージャーとして使用できる
var value = add(2, 3, +)
//=> 5

★ @noescape属性を付けたクロージャー

// @noescape属性が無い場合

var  theFunc: (Int -> Int)!
func setFunc(f: Int -> Int) { theFunc = f }

setFunc( { $0 + 2 } )
var value = theFunc(3)

// ---------------------

var method: (Int -> Int)!

func action(value: Int, closure: (Int -> Int)) {
    var result = closure(value)
    // クロージャーを保持できる
    method = closure
}

class Sample {
    var val = 2
    
    func sampleAction() {
        // クロージャー内では selfを付けてアクセスする
        action(5) { $0 * self.val }
    }
}

let sample = Sample()
sample.sampleAction()

// 保存したクロージャーを後から実行できる
var v = method(3)
//=> 6

// @noescape属性がある場合

var  theFunc: (Int -> Int)!
func setFunc(@noescape f: Int -> Int) { theFunc = f  } 
// エラー Cannot assign value of type '@noescape Int -> Int' to type '(Int -> Int)!'

// @noescape属性により保証されること
// クロージャはどこへも保持されない
// クロージャは非同期的に後から実行されることはない

// --------------------

var method: (Int -> Int)!

func action(value: Int,@noescape closure: (Int -> Int)) {
    
    var result = closure(value)
    // クロージャーを保持することはできない
    //method = closure
}

class Sample {
    var val = 2
    
    func sampleAction() {
        // selfが無くても使用できる
        action(5) { $0 * val }
    }
}

let sample = Sample()
sample.sampleAction()

★ @autoclosure属性を付けたクロージャー

// @autoclosure属性が無い場合

func f(pred: () -> Bool) {
    if pred() {
        println("It's true")
    }
}

f({2 > 1})
// "It's true"

// -------------

func method(cond: Bool, _ value: Int) {
    
    if !cond {
        print("value = \(value)")
    }
}

method(false, 10000)

// @autoclosure属性がある場合
// 引数がクロージャーとして遅延評価される様に指示する
// 短絡評価できる様になる

func f(pred: @autoclosure () -> Bool) {
    if pred() {
        println("It's true")
    }
}
f(2 > 1)
// It's true

// --------------

// @autoclosureを使用することにより引数をクロージャーにする 『() -> 戻り値の型』引数は『()』にしないとエラーになる
func method(cond: Bool, @autoclosure _ value: () -> Int) {
    
    if !cond {
        // クロージャーを実行
        print("value = \(value())")
    }
}

method(false, 10000)

★ ジネリック関数

func genericFunc<A, R>(f: A -> R, _ a: A)->R {
    return f(a)
}

func genericFunc<T: Comparable>(a: T, b: T) -> T {
    return a > b ? a : b
}

★ エラーをthrowする関数

enum MyError: ErrorType {
    case UnexpectedError
}

func myfunc() throws {
    throw MyError.UnexpectedError
}

do {
    try myfunc()
}
catch MyError.UnexpectedError {
    print("Error Caught")
}

★ 関数の戻り値を使用するように警告を出す属性を設定する

// @warn_unused_result属性を指定する

@warn_unused_result
func addTwoInts(a: Int, _ b: Int) -> Int {
    return a + b
}

addTwoInts(2, 3)
//=> warning Result of call to 'addTwoInts' is unused

// メッセージ付き
@warn_unused_result(message="戻り値を使用してください。")
//=> warning Result of call to 'addTwoInts' is unused: 戻り値を使用してください。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment