클로저 사용 시 인자 전달방법
함수의 인자로 클로저를 전달하는 경우를 생각해보자. 배열의 정렬된 사본을 만드는 sorted(_:,_:)
의 경우 대략 다음과 같은 시그니처를 가지고 있다.
func sorted<C: SequenceType>(source: C, isOrderedBefore: (C.Geneartor.Element, C.Generator.Element) -> Bool) -> [C.Generator.Element]
만약 정수 배열을 정렬한다고하면 다음과 같이 사용한다.
let arr = [5, 8, 2, 4, 2, 1, 7]
let sortedArr = sorted(arr, { (x:Int, y:Int) -> Bool in
return x < y
})
이 때 함수의 마지막 인자는 trailing closure
라고 해서 괄호 밖으로 빼낼 수 있다.
let sortedArr = sorted(arr){ (x:Int, y:Int) -> Bool in return x < y }
이때 클로저가 받는 각 인자는 순서대로 $0
, $1
, … 로 명명하는 것이 가능하다. 이 표현방식도 많이 알려져있는 형태이다.
let sortedArr = sorted(arr){ return $0 < $1 }
물론 단순히 표현식의 결과를 리턴하는 것이라면, 클로져 내부는 단순한 표현식이어도 된다.
let sortedArr = sorted(arr){ $0 < $1 }
비교연산자 <
도 역시 함수로 func <<T:Comparable>(lhs:T, rhs:T) -> Bool
로 sorted
함수가 요구하는 클로저의 시그니쳐와 동일한 시그니처를 가지고 있어서
let sortedArr = sorted(arr, <)
이렇게만 쓸 수도 있다.
다시 위의 예제 중에 sorted(arr){ $0 < $1 }
을 보자. 클로져로 전달되는 각각의 인자는 달러사인을 붙인 번호로 표시가 가능하다고 했는데, 경우에 따라서는 튜플로 전달된다고 볼 수도 있다. 그래서,
let sortedArr = sorted(arr){
let (x, y) = $0
return x < y
}
이렇게도 쓸 수 있다. 클로져내부에서 달러사인이 붙은 숫자를 하나만 쓴 경우, 복수의 인자는 튜플로 인식된다. 왜 이런 표현을 쓰냐면… 정규식을 사용하여 매치에 대해 각각 블럭호출을 하는 emuerateMatchesInsString(_:options:range:usingBlock)
함수의 경우에 클로져의 타입 시그니쳐가 (NSTextCheckingResult!, NSMatchingFlags, UnsafePointer<ObjCBool>) -> Void
인데, 이를 포멀한 형식으로 쓰려면 타이핑해야하는 양이 매우 많아진다. 그런데 특이하게 $0, $1, $2로 받아오는 동작이 되질 않는다. 버그인지 모르겠는데, 해당 블럭에 튜플로 파라미터들을 묶어서 던지는 것 같다. 따라서
var count = 0
regex.enumerateMatchesInString(str,
options:NSMatchingOptions(0),
range:NSMakeRange(0, (str as NSString).length)){
let (match, _, stop) = $0
println(match.range)
count++
if count >= 100 {
stop = true
}
}
추가: 다시 해보니 지금은 또 된다. 인자의 마지막 인덱스의 변수가 언급되면 언팩한 인자로 받는 듯 하다.
var error:NSError? = nil
var count = 0
let reg = NSRegularExpression(pattern:"d", options:.CaseInsensitive, error:&error)
let str = NSString(string:"gq2hga321gasdg4353y")
reg!.enumerateMatchesInString(str,
options:NSMatchingOptions(0),
range:NSMakeRange(0, str.length)){
println($0.range.location)
count++
if count > 3 {
$2.memory = false
}
}
참고로 여기서 stop
은 UnsafeMutablePointer<ObjCBool>
타입이다. 만약 Swift에서 C 포인터를 변경하고자 할 때는 직접 대입은 불가능하고 .memory
프로퍼티를 사용해야 한다.