Swift에서 if와 함께 range 연산자를 사용할 수 있습니까?


198

범위 연산자 .....<with 문 을 사용할 수 있습니까? 이런 식으로 할 수 있습니다 :

let statusCode = 204
if statusCode in 200 ..< 299 {
  NSLog("Success")
}

답변:


428

"pattern-match"연산자를 사용할 수 있습니다 ~=.

if 200 ... 299 ~= statusCode {
    print("success")
}

또는 패턴 패턴이있는 스위치 명령문 (패턴 일치 연산자를 내부적으로 사용) :

switch statusCode {
case 200 ... 299:
    print("success")
default:
    print("failure")
}

참고 ..<생략합니다 상위 값, 그래서 당신은 아마 원하는 범위의 의미 200 ... 299또는 200 ..< 300.

추가 정보 : 위의 코드가 최적화를 켜고 Xcode 6.3에서 컴파일 된 경우 테스트

if 200 ... 299 ~= statusCode

실제로 함수 호출은 전혀 생성되지 않으며 세 개의 어셈블리 명령 만 있습니다.

addq    $-200, %rdi
cmpq    $99, %rdi
ja  LBB0_1

이것은 정확히 동일한 어셈블리 코드입니다.

if statusCode >= 200 && statusCode <= 299

당신은 그것을 확인할 수 있습니다

xcrun -sdk macosx swiftc -O-방출 어셈블리 main.swift

Swift 2부터는 다음과 같이 쓸 수 있습니다.

if case 200 ... 299 = statusCode {
    print("success")
}

if 문에 새로 도입 된 패턴 일치를 사용합니다. "if"의 Swift 2-패턴 일치도 참조하십시오 .


1
이거 O (1)인가요? 또한 Swift가 Scala와 같은 switch 문에 짧은 손을 가지고 있다면 좋을 것입니다. 그러나 Swift에서 컴파일 타임에 모든 가능성을 항상 처리해야한다는 것을 감안할 때 실제로 실현 가능하지 않을 수 있습니다.
Sky

2
@Sky : 생성 된 어셈블리 코드에서 라이브러리 함수 func ~= (Range<A>, A) -> Bool가 호출 되었음을 알 수 있습니다 . 나는 할 생각 이 함수는 O (1)와 함께 작동.
Martin R

4
@Downvoter : 일부 설명 설명은 좋을 것이므로, 답을 개선하거나 고칠 수 있습니다 ...
Martin R

1
@MartinR 어셈블리 언어에 의해 호출되는 함수를 어떻게 알 수 있을까요? 멋진 답변을위한 +1
codester

3
@ codester : 명령 줄에서 코드를 컴파일 xcrun -sdk macosx swift -emit-assembly main.swift하고 어셈블리 코드를 검사했습니다. 그런 다음 xcrun swift-demangle ...호출 된 함수의 이름을 분리했습니다. 불행히도 Xcode는 Swift 파일에 대한 어셈블리 코드를 아직 만들 수 없으며 아마도 이후 버전에서 작동 할 것입니다.
Martin R

95

이 버전은 패턴 일치보다 읽기 쉽습니다.

if (200 ... 299).contains(statusCode) {
    print("Success")
}

2
정확히 내가 찾던 것
Nazim Kerimbekov

내가 얻을이 오류 => UPPERBOUND <LOWERBOUND과 범위를 형성 할 수 없습니다
Alfi

10

이것은 오래된 실이지만, 우리가 이것을 지나치게 생각하고있는 것 같습니다. 나에게 가장 좋은 대답은

if statusCode >= 200 && statusCode <= 299

없어

if 200 > statusCode > 299

내가 알고있는 양식과 다른 제안 된 솔루션은 함수 호출을 수행하고 있는데, 읽기가 어렵고 실행이 느릴 수 있습니다. 패턴 일치 방법은 알아두면 유용한 기술이지만이 문제에는 적합하지 않은 것 같습니다.

편집하다:

개인적으로 패턴 일치 연산자가 끔찍한 것을 발견하고 컴파일러가 if x in 1...100구문 을 지원하기를 바랍니다 . 그것은 훨씬 더 직관적이고 읽기 쉬운 sooooo입니다if 1...100 ~= x


1
이 버전을 읽는 것이 더 낫습니다 . "범위 연산자를 사용할 수 있습니까?"라는 명확한 질문에 답하려고했습니다. – 그러나 Xcode 6.3 베타 (최적화 된 모드에서)는 if 200 ... 299 ~= statusCode함수 호출없이 정확히 세 개의 어셈블리 명령어를 생성합니다. :)
Martin R

13
실제로 if 200 ... 299 ~= statusCode다음 과 동일한 어셈블리 코드를 제공합니다if statusCode >= 200 && statusCode <= 299
Martin R

6
이 조건이 초당 수천 번 방문하는 중요한 섹션에 있지 않는 한 함수 호출 오버 헤드에 대한 걱정은 조기 최적화입니다. 그럼에도 불구하고 함수 호출 의 비용보다는 함수 호출의 기능에 대해 더 걱정 하고 있습니다. 그럼에도 불구하고 비용이 들지 않는다는 것을 증명 해준 @MartinR의 훌륭한 직업.
rickster

1
@rickster, 충분히 사실. 나는 습관의 문제로 비효율적 인 것보다 효율적인 구조체를 선호하는 경향이 있습니다 (가독성이 비슷하다고 가정). 내가 너무 많은 시간을 낭비하지는 않지만 여전히 다른 접근법의 비용이 얼마인지 아는 것은 비용을 지불합니다.
Duncan C

1
이것은 nitpicking이지만 귀하의 if 문이 @SerhiiYakovenko가 게시 한 답변보다 읽기 쉽고 이해하기 쉽다는 귀하의 의견에 동의하지 않습니다. DRY를 기준으로 간단히 "statusCode"라는 이름을 두 번 사용합니다. "statusCode"대신 "statusValue"라는 다른 변수를 사용해야한다고 결정한 후 심야의 bleary-eyed 디버깅 세션에서 다른 변수가 아닌 변수 이름 중 하나를 변경하는 실수를 범할 수 있습니다. .
RenniePet

3

401을 제외한 4xx 오류를 확인하고 싶었습니다. 코드는 다음과 같습니다.

let i = 401

if 400..<500 ~= i, i != 401 {
    print("yes")
} else {
    print("NO")
}

2

구현이 비효율적 인 것으로 나타났습니다 때까지 너무 범위 .contains () 연산자를 선호 - https://oleb.net/blog/2015/09/swift-ranges-and-intervals/

범위를 사용하여 조건 x <0을 나타낼 수 있습니다. (Int.min .. <0) .contains (x)는 정확히 같습니다. 그래도 속도가 훨씬 느립니다. contains (_ :)의 기본 구현은 전체 컬렉션을 순회하며 최악의 경우 9 배의 5 배 루프를 실행하는 것은 저렴하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.