★ インスタンスメソッド
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: 戻り値を使用してください。