Closures
Swift:
Closures are self-contained blocks of functionality that can be passed around and used in your code.
Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
Global and nested functions, as introduced in Functions, are actually special cases of closures.
3種類:
Global functions are closures that have a name and do not capture any values. Nested functions are closures that have a name and can capture values from their enclosing function. Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
C#:
2種類:
Closure Expressions
The Sorted Function
Swiftのsortedの例:
10> let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
names: [String] = 5 values {
[0] = "Chris"
[1] = "Alex"
[2] = "Ewa"
[3] = "Barry"
[4] = "Daniella"
}
11> func backwards(s1: String, s2: String) -> Bool { return s1 > s2 }
12> sorted(names, backwards)
$R2: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
Closure Expression Syntax
Swiftの クロージャ:
13> {(s1: String, S2: String) -> Bool in return s1 > s2 }
$R3: (String, String) -> Bool = ($__lldb_expr18`__lldb_expr_17.(closure #1) at repl.swift:13)
14> sorted(names,{(s1:String, s2:String)->Bool in return s1 > s2})
$R4: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
C#:
csharp> Func<string, string, int> lambda = (i,j) => -1 * i.CompareTo(j);
csharp> lambda.GetType()
System.Func`3[System.String,System.String,System.Int32]
var names = new string[]{"Chris", "Alex", "Ewa", "Barry", "Daniella"};
foreach(var i in names ){ Console.Write(i);Console.Write(",");};Console.WriteLine();
Chris,Alex,Ewa,Barry,Daniella,
Array.Sort(names, (o1, o2 ) => -1 * o1.CompareTo(o2) );
foreach(var i in names ){ Console.Write(i);Console.Write(",");};Console.WriteLine();
Ewa,Daniella,Chris,Barry,Alex,
Inferring Type From Context
Swift: 型の推論
15> sorted(names, { s1, s2 in return s1 > s2 } )
$R5: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
C#: 同じく
Array.Sort(names, (o1, o2 ) => -1 * o1.CompareTo(o2) );
Implicit Returns from Single-Expression Closures
Swift: 単一文だとreturnもいらない
16> sorted(names, { s1, s2 in s1 > s2 } )
$R6: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
C#: 同じ
Shorthand Argument Names
Swift: "$引数の番号" で、引数リストも省略
17> sorted(names, { $0 > $1 } )
$R7: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
C#: これは無いと思う
Operator Functions
Swift: Stringに ">" 演算子があって、引数2個とることまでわかっているので...
18> sorted(names, >)
$R8: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
Trailing Closures
- 引数の最後にクロージャを取るならば、クロージャを関数呼び出しの外側における...
A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports
Swift:
19> sorted(names) { $0 > $1 }
$R9: [String] = 5 values {
[0] = "Ewa"
[1] = "Daniella"
[2] = "Chris"
[3] = "Barry"
[4] = "Alex"
}
31> func my(i: Int, j: Int, closure: (Int, Int)->Int )->Int{
32. return 2 * closure(i,j)
33. }
35> my(3,5){ $0 * $1 }
$R12: Int = 30
C# : ないと思う
Capturing Values
A closure can capture constants and variables from the surrounding context in which it is defined.
31> func my(i: Int, j: Int, closure: (Int, Int)->Int )->Int{
32. return 2 * closure(i,j)
33. }
36> var a=1
a: Int = 1
37> my(3,5){ $0 * $1 + a }
$R13: Int = 32
The closure can then refer to and modify the values of those constants and variables from within its body,
42> var b = 0
b: Int = 0
43> my(3,5){ b = $0 * $1; return b + a}
$R18: Int = 32
44> b
$R19: Int = 15
even if the original scope that defined the constants and variables no longer exists.
53> func getinc(amount: Int)-> ()->Int {
54. var grand_total=0
55. func inc() -> Int {
56. grand_total += amount
57. return grand_total
58. }
59. return inc
60. }
62> var x=getinc(10)
x: () -> Int = ($__lldb_expr77`partial apply forwarder for __lldb_expr_76.(getinc (Swift.Int) -> () -> Swift.Int).(inc #1) (())Swift.Int at repl76.swift)
68> x();x();x();x()
$R23: Int = 40
69> var y = getinc(1)
y: () -> Int = ($__lldb_expr77`partial apply forwarder for __lldb_expr_76.(getinc (Swift.Int) -> () -> Swift.Int).(inc #1) (())Swift.Int at repl76.swift)
70> y();y();y();y()
$R24: Int = 4
C#: Func を返す Func を作成して呼び出すラッパーを用意。外側のFuncの定義にコンテキストを持たせる。
public static Func<int> GetInc(int unit)
{
return (new Func<Func<int>>(() => {
int x = 0;
return new Func<int>(() => { x += unit; return x; });
}))();
}
var x = GetInc(10);
var y = GetInc(1);
var i = 0;
var j = 0;
for( int k=0 ; k< 4; k++ ){
i = x(); j=y();
}
Console.WriteLine(string.Format("{0},{1}", i,j));
40,4
Closures Are Reference Types
Swift: 参照型ということ
72> var z = x
z: () -> Int = ($__lldb_expr77`partial apply forwarder for __lldb_expr_76.(getinc (Swift.Int) -> () -> Swift.Int).(inc #1) (())Swift.Int at repl76.swift)
73> z()
$R26: Int = 60
C# : 同じく
var z = x;
Console.WriteLine(z());
50