Swift 스위치 명령문보다 작거나


145

switchSwift의 문장에 익숙 하지만이 코드를 다음으로 대체하는 방법이 궁금합니다 switch.

if someVar < 0 {
    // do something
} else if someVar == 0 {
    // do something else
} else if someVar > 0 {
    // etc
}

이것은 흥미로운 질문이지만 스위치를 사용하는 코드는 if 문보다 읽기 쉽지 않습니다. 당신이 할 수 있다고해서 꼭 그래야하는 것은 아닙니다.
Rog

답변:


241

한 가지 방법이 있습니다. 가정 someVar되는 IntComparable, 선택적 새로운 변수로 피연산자를 할당 할 수 있습니다. where키워드를 사용하여 원하는 범위를 지정할 수 있습니다 .

var someVar = 3

switch someVar {
case let x where x < 0:
    print("x is \(x)")
case let x where x == 0:
    print("x is \(x)")
case let x where x > 0:
    print("x is \(x)")
default:
    print("this is impossible")
}

이것은 약간 단순화 될 수 있습니다 :

switch someVar {
case _ where someVar < 0:
    print("someVar is \(someVar)")
case 0:
    print("someVar is 0")
case _ where someVar > 0:
    print("someVar is \(someVar)")
default:
    print("this is impossible")
}

where범위 일치로 키워드를 완전히 피할 수도 있습니다 .

switch someVar {
case Int.min..<0:
    print("someVar is \(someVar)")
case 0:
    print("someVar is 0")
default:
    print("someVar is \(someVar)")
}

9
default: fatalError()가능한 논리 오류를 조기에 감지하는 것이 좋습니다 .
Martin R

1
감사! 이 예제는 매우 유용하며 내 문제를 해결합니다! (다른 예제들도 좋았지 만 당신의 것이 나에게 가장 도움이되었습니다)
Pieter

1
@MartinR assertionFailure은 특히 ​​팀에서 작업 할 때 더 안전한 옵션 인 것 같습니다.
Michael Voline

119

Swift 5에서는 if 문을 대체하기 위해 다음 스위치 중 하나를 선택할 수 있습니다.


1 번 스위치를 사용 PartialRangeFrom하고PartialRangeUpTo

let value = 1

switch value {
case 1...:
    print("greater than zero")
case 0:
    print("zero")
case ..<0:
    print("less than zero")
default:
    fatalError()
}

# 2 스위치를 사용 ClosedRange하고Range

let value = 1

switch value {
case 1 ... Int.max:
    print("greater than zero")
case Int.min ..< 0:
    print("less than zero")
case 0:
    print("zero")
default:
    fatalError()
}

# 3 where 절과 함께 스위치 사용

let value = 1

switch value {
case let val where val > 0:
    print("\(val) is greater than zero")
case let val where val == 0:
    print("\(val) is zero")
case let val where val < 0:
    print("\(val) is less than zero")
default:
    fatalError()
}

# 4 where 절과 함께 스위치 사용 _

let value = 1

switch value {
case _ where value > 0:
    print("greater than zero")
case _ where value == 0:
    print("zero")
case _ where value < 0:
    print("less than zero")
default:
    fatalError()
}

# 5 RangeExpression프로토콜 ~=(_:_:)운영자 와 함께 스위치 사용

let value = 1

switch true {
case 1... ~= value:
    print("greater than zero")
case ..<0 ~= value:
    print("less than zero")
default:
    print("zero")
}

# 6 Equatable프로토콜 ~=(_:_:)운영자 와 함께 스위치 사용

let value = 1

switch true {
case value > 0:
    print("greater than zero")
case value < 0:
    print("less than zero")
case 0 ~= value:
    print("zero")
default:
    fatalError()
}

# 7 스위치를 사용하여 PartialRangeFrom, PartialRangeUpTo그리고 RangeExpressionS ' contains(_:)방법

let value = 1

switch true {
case (1...).contains(value):
    print("greater than zero")
case (..<0).contains(value):
    print("less than zero")
default:
    print("zero")
}

1
# 2에서 기본 사례가 필요한 이유는 무엇입니까? 범위가 Int.min에서 Int.max까지라면 무엇이 남는가?
μολὼν.λαβέ

와우, 멋진 옵션 목록. 이 작업을 수행하는 방법에는 여러 가지가 있습니다.
Christopher Pickslay

2
개요는 양호하지만 0과 1 사이의 숫자는 설명되지 않으므로 결함이 있습니다. 0.1때문에 치명적인 오류가 발생 1...하는 경우이 솔루션은 1에서 커버 숫자 만 작동 그래서 value입니다 Int변수 유형은 어떤 컴파일러 오류없이 기능 구분을 변경하면 있기 때문에 그 위험합니다.
Manuel

1
Double 유형에 대한 솔루션이 올바르게 작동하지 않습니다. case 1 ... : print ( "0보다 큰") 0보다 크지 않거나 1보다 크거나 같습니다.
Vlad

20

switch후드 아래 의 문장은 ~=연산자를 사용합니다 . 그래서 이거:

let x = 2

switch x {
case 1: print(1)
case 2: print(2)
case 3..<5: print(3..<5)
default: break
}

이것에 대한 설탕 제거 :

if 1          ~= x { print(1) }
else if 2     ~= x { print(2) }
else if 3..<5 ~= x { print(3..<5) }
else {  }

표준 라이브러리 참조를 살펴보면 ~=오버로드가 무엇 을 수행 하는지 정확하게 알 수 있습니다 : 포함은 범위 일치 및 동일 항목과 동일합니다. (포함되지 않은 열거 형 대소 문자는 표준 라이브러리의 함수가 아닌 언어 기능입니다)

왼쪽의 직선 부울과 일치하지 않는 것을 볼 수 있습니다. 이러한 종류의 비교를 위해서는 where 문을 추가해야합니다.

~=운전자 에게 과부하가 걸리지 않으면 ... (일반적으로 권장 되지 않음) 한 가지 가능성은 다음과 같습니다.

func ~= <T> (lhs: T -> Bool, rhs: T) -> Bool {
  return lhs(rhs)
}

왼쪽의 부울을 오른쪽의 매개 변수로 반환하는 함수와 일치합니다. 사용할 수있는 종류는 다음과 같습니다.

func isEven(n: Int) -> Bool { return n % 2 == 0 }

switch 2 {
case isEven: print("Even!")
default:     print("Odd!")
}

귀하의 경우 다음과 같은 진술이있을 수 있습니다.

switch someVar {
case isNegative: ...
case 0: ...
case isPositive: ...
}

하지만 지금은 새로운 정의해야 isNegative하고 isPositive기능을. 더 많은 연산자를 오버로드하지 않으면 ...

일반 접두사 연산자를 오버로드하여 접두사 또는 접미사 연산자로 만들 수 있습니다. 예를 들면 다음과 같습니다.

postfix operator < {}

postfix func < <T : Comparable>(lhs: T)(_ rhs: T) -> Bool {
  return lhs < rhs
}

이것은 다음과 같이 작동합니다.

let isGreaterThanFive = 5<

isGreaterThanFive(6) // true
isGreaterThanFive(5) // false

이를 이전 함수와 결합하면 switch 문이 다음과 같이 보일 수 있습니다.

switch someVar {
case 0< : print("Bigger than 0")
case 0  : print("0")
default : print("Less than 0")
}

이제는 실제로 이런 종류의 것을 사용해서는 안됩니다. 당신은 (아마도) where진술을 고수하는 것이 좋습니다 . 즉, 스위치 문 패턴

switch x {
case negative:
case 0:
case positive:
}

또는

switch x {
case lessThan(someNumber):
case someNumber:
case greaterThan(someNumber):
}

고려할만한 가치가있는 것 같습니다.


1
질문에 대한 당신의 대답은 어디에 있습니까? 찾을 수 없습니다.
Honey

1
case 3 .. <5 : print (3 .. <5)-첫 번째 단락에서 말 그대로. 이 답변은 과소 평가되었습니다. 너무 많은 코드를 저장합니다.
카림

14

당신은 할 수 있습니다 :

switch true {
case someVar < 0:
    print("less than zero")
case someVar == 0:
    print("eq 0")
default:
    print("otherwise")
}

6

누군가 이미 case let x where x < 0:여기에 게시했기 때문에 where someVaris에 대한 대안입니다 Int.

switch someVar{
case Int.min...0: // do something
case 0: // do something
default: // do something
}

그리고 여기에 대한 대안 someVar이 있습니다 Double:

case -(Double.infinity)...0: // do something
// etc

6

이것은 범위가 어떻게 보이는지입니다.

switch average {
case 0..<40: //greater or equal than 0 and less than 40
    return "T"
case 40..<55: //greater or equal than 40 and less than 55
    return "D"
case 55..<70: //greater or equal than 55 and less than 70
    return "P"
case 70..<80: //greater or equal than 70 and less than 80
    return "A"
case 80..<90: //greater or equal than 80 and less than 90
    return "E"
case 90...100: //greater or equal than 90 and less or equal than 100
    return "O"
default:
    return "Z"
}

3

<0표현은 (이상?) 작동하지 않습니다 나는이와 결국 있도록 :

스위프트 3.0 :

switch someVar {
    case 0:
        // it's zero
    case 0 ..< .greatestFiniteMagnitude:
        // it's greater than zero
    default:
        // it's less than zero
    }

1
SWIFT 3.0 X_MAX로 대체되었습니다 .greatestFiniteMagnitude, 즉 Double.greatestFiniteMagnitude, CGFloat.greatestFiniteMagnitude등등 그래서 일반적으로, 당신은 할 수 case 0..< .greatestFiniteMagnitude의 종류부터 someVar이미 알려져있다
Guig

@Dorian Roy 운영자 var timeLeft = 100 switch timeLeft {case 0...<=7200: print("ok") default:print("nothing") }가 왜 <=인식되지 않습니까? 내가 동등하게 쓰지 않으면 효과가 있습니다. 감사합니다
bibscy

@bibscy 폐쇄 범위 연산자를 사용하려고합니다 case 0...7200:. 연산자 <=는 비교 연산자입니다. 스위치에서는 범위 연산자 만 사용할 수 있습니다 (문서 참조)
Dorian Roy

대단 했어. 이 오류를 얻고 있었다 '지능'유형의 값을 일치시킬 수없는 '범위 <더블>'형식의 발현 패턴을 내이 때문에 someVar이었다 Int내가해야 할 일을했을 Double(의 somevar를가 ... 작동하도록`)

2

Swift 4가 문제를 해결하게 된 것을 기쁘게 생각합니다.

3의 해결 방법으로 다음을 수행했습니다.

switch translation.x  {
case  0..<200:
    print(translation.x, slideLimit)
case  -200..<0:
    print(translation.x, slideLimit)
default:
    break
}

작동하지만 이상적이지 않음

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