LoginSignup
4
4

More than 5 years have passed since last update.

Swift vs. C# : Closures

Posted at

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
4
4
0

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
4
4