Closure

작성일

Closure

  • 이름이 없다.
  • func이랑 유사하다.

function

func myScore(a: Int) -> String {
  return "\(a)점"
}

let score = myScore
score

를 출력해보면,

(Int) -> String

이라고 나온다. myScore에 매개변수를 넣지 않았기 때문이다. 만약에 60이라고 넣으면,

func myScore(a: Int) -> String {
  return "\(a)점"
}

let score = myScore(a: 60)
score

출력해보면,

60점

이라고 나온다.

closure

let myScore2 = { (a: Int) -> String in
  return "\(a)점"
}

myScore2

를 출력해보면 똑같이

(Int) -> String

라고 나온다.


축약 (생략)

let myScore2 = { (a: Int) -> String in
  return "\(a)점"
}

일 경우에(return 줄이 한줄일 경우에)

let myScore2 = { (a: Int) -> String in
  "\(a)점"
}

return 생략이 가능하다.
또,

let myScore3 = { (a: Int) -> String in
  "\(a)점"
}

을 보면, return 줄을 보면 String타입이기 때문에,
위에(a: Int) -> String에서 String타입이라고 타입추론이 가능하다.
따라서

let myScore4 = { (a: Int) in
  "\(a)점"
}

이렇게생략할 수 있다.
또 다르게

let myScore5: (Int) -> String = { a in
  "\(a)점"
}

이렇게 사용 할 수 있다.
또 다른 스타일은

let myScore6: (Int) -> String = {
  return "\($0)점"
}

받은 파라미터를 생략할 수 있다.(대신($인덱스)를 사용해줘야 한다.)


사용하는 느낌

  • 조건 -> 특정한 글자가 포함된 것을 찾는다.
let names = ["apple", "air", "brown", "red", "orange", "blue", "candy"]

func someFind(find: String) -> [String] {
  var newNames = [String]()

  for name in names{
    name.contains(find){
      newNames.append(name)
    }
  }

  return newNames
}

someFind(find: "a")

를 출력해보면

["apple", "air", "orange", "candy"]

가 나온다.
하지만, 만약에 “입력한 글자로 시작하는 첫 글자를 찾는다.”라는 기능을 추가시키려면,
Closure 를 사용하면 된다.

let names = ["apple", "air", "brown", "red", "orange", "blue", "candy"]

let containsSomeText: (String, String) -> Bool = {name, find in
  if name.contains(find) {
    return true
  }
  return false
}

let isStartSomeText: (String, String) -> Bool = { name, find in
  if name.first?.description == find {
    return true
  }
  return false  
}

func find(findStirng: Stirng, condition: (String, String) -> Bool) -> [Stirng] {
  var newNames = [String]()

  for name in names {
    if condition(name, findString) {
      newNames.append(name)
    }
  }

  return newNames
}

find(findStirng: "a", condition: containsSomeText)
find(findStirng: "a", condition: isStartSomeText)

위 코드를 보면, 같은 find함수지만, condition이 뭔지에 따라 로직이 바뀐다. 즉 다양한 기능을 추가할 수 있다.


.sort()는 return이 있는데
.sorted()는 return이 없다.
즉, .sort()는 값을 받아와야한다.(원본의 순서가 바뀐다.)
.sorted()는 값을 변경하지 않는다.(원본은 그대로 있다.)

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

//sort
names.sort { (lhs, rhs) -> Bool in
  return lhs > rhs
}

출력하면

["Alex", "Barry", "Chris", "Daniella", "Ewa"]

으로 출력이 된다.

names.sort { (lhs, rhs) -> Bool in
  return lhs > rhs
}

하지만 위 코드를 더 짧게 변경이 가능하다.
Closure를 사용해보면,
return생략가능, return타입도 생략가능, 파라미터(lhs, rhs)생략가능
단,생략하면 in도 같이 생략해야함. 생략하면 이름을 가져올수 없어서 $0, $1로 정의된 용어로 변경해서 가져와 사용할수 있다.
따라서,

names.sort{ $0 < $1 }

이런식으로 짧게 단축시킬 수 있다.
그리고

names.sort(by: { $0 < $1 } )

이거와 같지만, 받는값이 하나라서 by를 생략한 것이다.
또 다른형태로 볼수 있는데,

names.sort(by: { $0 < $1 } )

names.sort(by: < )

와 같다.
그 이유는 < 자체가 Closure이미 때문이다.(단, 이떄는 by를 꼭 써줘야 한다.)