Swift @autoclosure를 사용하는 방법


148

assertSwift에서을 쓸 때 첫 번째 값이 다음과 같이 입력되었음을 알았습니다.

@autoclosure() -> Bool

T통해 존재를 테스트하기 위해 일반 값 을 반환하는 오버로드 된 메소드 를 사용합니다 LogicValue protocol.

그러나 당면한 문제를 엄격히 고수하십시오. @autoclosure를 반환하는 것으로 보입니다 Bool.

매개 변수를 사용하지 않고 Bool을 반환하는 실제 클로저를 작성하면 작동하지 않습니다. 클로저를 호출하여 컴파일되도록하십시오.

assert({() -> Bool in return false}(), "No user has been set", file: __FILE__, line: __LINE__)

그러나 단순히 Bool을 전달하면 작동합니다.

assert(false, "No user has been set", file: __FILE__, line: __LINE__)

무슨 일이야? 무엇입니까 @autoclosure?

편집 : @auto_closure 이름이 변경되었습니다@autoclosure

답변:


269

하나의 인수를 취하는 함수, 인수를 취하지 않는 간단한 클로저를 고려하십시오.

func f(pred: () -> Bool) {
    if pred() {
        print("It's true")
    }
}

이 함수를 호출하려면 클로저를 전달해야합니다

f(pred: {2 > 1})
// "It's true"

중괄호를 생략하면 표현식이 전달되며 오류입니다.

f(pred: 2 > 1)
// error: '>' produces 'Bool', not the expected contextual result type '() -> Bool'

@autoclosure표현식 주위에 자동 폐쇄를 작성합니다. 따라서 호출자가와 같은 표현식을 작성하면 에 전달 2 > 1되기 {2 > 1}전에 자동으로 클로저로 래핑됩니다 f. 따라서 이것을 함수에 적용하면 f:

func f(pred: @autoclosure () -> Bool) {
    if pred() {
        print("It's true")
    }
}

f(pred: 2 > 1)
// It's true

따라서 클로저로 감싸지 않고도 표현식으로 작동합니다.


2
실제로 마지막 것은 작동하지 않습니다. 그것은해야한다f({2 >1}())
루이 페레스

@JoelFischer @JackyBoy와 동일한 내용을보고 있습니다. 전화하기 f(2 > 1). 로 전화 f({2 > 1})가 실패합니다 error: function produces expected type 'Bool'; did you mean to call it with '()'?. 나는 놀이터와 Swift REPL로 테스트했습니다.
Ole Begemann

어떻게 든 마지막 답변으로 두 번째에서 마지막 답변을 읽었습니다. 나는 다시 확인해야하지만, 기본적으로 클로저 내부에 클로저를 넣는 것처럼 이해하지 못하면 실패한 경우 의미가 있습니다.
Joel Fischer

3
그들이 그 한 이유에 대한 블로그 게시물이 developer.apple.com/swift/blog/?id=4을
모하메드 - 테드

5
좋은 설명입니다. 그것은, 그래서 스위프트 1.2 'autoclosure'이제 매개 변수 선언의 속성임을 유의하십시오func f(@autoclosure pred: () -> Bool)
마사

30

다음은 실용적인 예입니다. 내 print재정의 (Swift 3) :

func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    Swift.print(item(), separator:separator, terminator: terminator)
    #endif
}

당신이 말할 때 print(myExpensiveFunction()), 내 print재정의 print는 Swift를 어둡게 하고 호출됩니다. myExpensiveFunction()따라서 폐쇄로 싸여져 평가되지 않습니다 . 우리는 릴리스 모드에 있다면, 그것은 것입니다 적이 있기 때문에, 평가되지 item()호출되지 않습니다. 따라서 print릴리스 모드에서 인수를 평가하지 않는 버전이 있습니다.


나는 파티에 늦었지만 평가의 영향은 무엇 myExpensiveFunction()인가?. 자동 폐쇄를 사용하는 대신 다음과 같이 인쇄하도록 함수를 전달하면 print(myExpensiveFunction)어떤 영향을 미칩니 까? 감사.
crom87

11

문서의 auto_closure에 대한 설명 :

매개 변수 유형이 ()이고 표현식 유형을 리턴하는 함수 유형에 auto_closure 속성을 적용 할 수 있습니다 (유형 속성 참조). 자동 폐쇄 함수는 표현식 자체 대신 지정된 표현식에 대한 암시 적 폐쇄를 캡처합니다. 다음 예제는 매우 간단한 어설 션 함수를 정의 할 때 auto_closure 속성을 사용합니다.

그리고 여기 애플과 함께 사용하는 예제가 있습니다.

func simpleAssert(condition: @auto_closure () -> Bool, message: String) {
    if !condition() {
        println(message)
    }
}
let testNumber = 5
simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")

기본적으로 의미하는 것은 부울 식을 클로저 대신 첫 번째 인수로 전달하고 자동으로 클로저를 생성한다는 것입니다. 따라서 부울식이 기 때문에 메서드에 false를 전달할 수 있지만 클로저를 전달할 수는 없습니다.


15
실제로 @auto_closure여기 를 사용할 필요는 없습니다 . 코드가 없으면 제대로 작동합니다 func simpleAssert(condition: Bool, message: String) { if !condition { println(message) } }. 사용 @auto_closure이 반복 인수를 평가해야하는 경우 (예를 들어, 당신이 구현 된 경우 while-like 기능) 또는 인수 (당신이 구현 된 경우 예를 들어, 단락의 지연 평가에 필요 &&).
nathan

1
@nathan 안녕하세요, nathan. 당신은 내게의 사용에 관한 샘플 인용 시겠어요 autoclosureA를 while-like 기능을? 나는 그것을 이해하지 못하는 것 같습니다. 미리 감사드립니다.
Unheilig

@connor Swift 3에 대한 답변을 업데이트하고 싶을 수도 있습니다.
jarora

4

이것은 https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/ 의 유용한 사례를 보여줍니다@autoclosure

이제 첫 번째 매개 변수로 전달 된 조건식이 자동으로 클로저 표현식으로 랩핑되고 루프 주위에서 매번 호출 될 수 있습니다.

func until<L: LogicValue>(pred: @auto_closure ()->L, block: ()->()) {
    while !pred() {
        block()
    }
}

// doSomething until condition becomes true
until(condition) {
    doSomething()
}

2

클로저 호출에서 중괄호를 제거하는 방법 일뿐입니다. 간단한 예는 다음과 같습니다.

    let nonAutoClosure = { (arg1: () -> Bool) -> Void in }
    let non = nonAutoClosure( { 2 > 1} )

    let autoClosure = { (arg1: @autoclosure () -> Bool) -> Void in }
    var auto = autoClosure( 2 > 1 ) // notice curly braces omitted

0

@autoclosure일반 closure은 원시 함수 를 승인하는 동안 요리 된 함수 (또는 리턴 된 유형)를 승인하는 함수 매개 변수입니다.

  • @autoclosure 인수 유형 매개 변수는 '()'이어야합니다.
    @autoclosure ()
  • @ autoclosure는 적절한 반환 유형 만 가진 모든 함수를 수락합니다.
  • 마감 결과는 수요에 따라 계산됩니다.

예를 보자

func testClosures() {

    //closures
    XCTAssertEqual("fooWithClosure0 foo0", fooWithClosure0(p: foo0))
    XCTAssertEqual("fooWithClosure1 foo1 1", fooWithClosure1(p: foo1))
    XCTAssertEqual("fooWithClosure2 foo2 3", fooWithClosure2(p: foo2))

    XCTAssertEqual("fooWithClosure2 foo2 3", fooWithClosure2(p: { (i1, i2) -> String in
        return "fooWithClosure2 " + "foo2 " + String(i1 + i2)
    }))

    //@autoclosure
    XCTAssertEqual("fooWithAutoClosure HelloWorld", fooWithAutoClosure(a: "HelloWorld"))

    XCTAssertEqual("fooWithAutoClosure foo0", fooWithAutoClosure(a: foo0()))
    XCTAssertEqual("fooWithAutoClosure foo1 1", fooWithAutoClosure(a: foo1(i1: 1)))
    XCTAssertEqual("fooWithAutoClosure foo2 3", fooWithAutoClosure(a: foo2(i1: 1, i2: 2)))

}

//functions block
func foo0() -> String {
    return "foo0"
}

func foo1(i1: Int) -> String {
    return "foo1 " + String(i1)
}

func foo2(i1: Int, i2: Int) -> String {
    return "foo2 " + String(i1 + i2)
}

//closures block
func fooWithClosure0(p: () -> String) -> String {
    return "fooWithClosure0 " + p()
}

func fooWithClosure1(p: (Int) -> String) -> String {
    return "fooWithClosure1 " + p(1)
}

func fooWithClosure2(p: (Int, Int) -> String) -> String {
    return "fooWithClosure2 " + p(1, 2)
}

//@autoclosure
func fooWithAutoClosure(a: @autoclosure () -> String) -> String {
    return "fooWithAutoClosure " + a()
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.