assert
Swift에서을 쓸 때 첫 번째 값이 다음과 같이 입력되었음을 알았습니다.
@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
답변
하나의 인수를 취하는 함수, 인수를 취하지 않는 간단한 클로저를 고려하십시오.
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
재정의 print
는 Swift를 어둡게 하고 호출됩니다. myExpensiveFunction()
따라서 폐쇄로 싸여져 평가되지 않습니다 . 우리는 릴리스 모드에 있다면, 그것은 것입니다 적이 있기 때문에, 평가되지 item()
호출되지 않습니다. 따라서 print
릴리스 모드에서 인수를 평가하지 않는 버전이 있습니다.
답변
문서의 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를 전달할 수 있지만 클로저를 전달할 수는 없습니다.
답변
이것은 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()
}
답변
클로저 호출에서 중괄호를 제거하는 방법 일뿐입니다. 간단한 예는 다음과 같습니다.
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
답변
@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()
}