programing

Swift @autoclosure 사용방법

showcode 2023. 4. 15. 09:40
반응형

Swift @autoclosure 사용방법

나는 글을 쓸 때 알아차렸다.assertSwift에서는 첫 번째 값이 다음과 같이 입력됩니다.

@autoclosure() -> Bool

일반적인 것을 반환하기 위해 과부하된 메서드를 사용하여T값을 사용하여 존재 여부를 테스트합니다.LogicValue protocol.

하지만 엄밀하게 당면한 문제에 집착하고 있다.필요한 것 같습니다.@autoclosure그러면 a가 반환됩니다.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

하나의 인수를 사용하는 함수, 즉 인수를 사용하지 않는 단순한 닫힘을 고려합니다.

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

그래서 마무리로 포장할 필요 없이 표현만으로 동작합니다.

여기 실용적인 예가 있습니다.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오버라이드(override)는 스위프트의 것을 무색하게 한다.print라고 불리고 있습니다. myExpensiveFunction()따라서 폐쇄로 감싸지고 평가되지 않습니다.Release 모드일 경우 평가되지 않습니다.item()호출되지 않습니다.이렇게 해서 Version이 있습니다.print릴리스 모드에서는 인수를 평가하지 않습니다.

문서에서 auto_closure에 대한 설명:

auto_closure Atribute는 파라미터 타입이 ()이고 식 타입을 반환하는 함수유형에 적용할 수 있습니다(Type Attributes 참조).자동 노출 함수는 식 자체 대신 지정된 식에 대한 암묵적 닫힘을 캡처합니다.다음 예제에서는 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를 메서드에 전달할 수 있습니다.

은 유용한 입니다.@autoclosure https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/httpsairspeedvelocity.net/2014/06/28//

이제 까지 첫 번째 매개 변수로 전달된 조건부 식은 자동으로 닫힘 식으로 정리되어 루프 주위를 돌 때마다 호출할 수 있습니다.

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

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

이것은 클로즈 콜에서 컬리브레이스를 제거하는 단순한 방법입니다.

    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

@loclosure(공개)

@autoclosure는 내부 변환합니다.closure [대략]

장점:

  • assert(2 == 5, "failed")
  • 중괄호는 사용되지 않습니다.

단점

  • 읽기 어렵다.함수를 내부로 전달했을 때@autoclosure이 함수가 지연될지는 명확하지 않습니다(내부 폐쇄이기 때문입니다). fooWithAutoClosure(a: foo0())-foo0()되지 않습니다.

고압 인클로저를 과도하게 사용하면 코드를 이해하기 어려울 수 있습니다.컨텍스트와 기능명은 평가가 연기되고 있음을 명확히 해야 한다.

공식 문서

  • @autoclosure 변수를 하지 않습니다.
    func foo(p: @autoclosure () -> Void)
    
  • @autoclosure적절한 반환 유형만 있는 함수를 받아들인다.

기타 예

//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()
}
//test closures
func testClosures() {
    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)
    }))
}
//test @autoclosure
func testAutoClosures() {
    XCTAssertEqual("fooWithAutoClosure HelloWorld", fooWithAutoClosure(a: "HelloWorld")) //"HelloWorld" is String as returned value of @autoclosure
    
    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)))
}

언급URL : https://stackoverflow.com/questions/24102617/how-to-use-swift-autoclosure

반응형