Swift의 정적 함수 변수


96

Swift의 함수에 로컬로만 범위가 지정된 정적 변수를 선언하는 방법을 알아 내려고합니다.

C에서는 다음과 같이 보일 수 있습니다.

int foo() {
    static int timesCalled = 0;
    ++timesCalled;
    return timesCalled;
}

Objective-C에서는 기본적으로 동일합니다.

- (NSInteger)foo {
    static NSInteger timesCalled = 0;
    ++timesCalled;
    return timesCalled;
}

그러나 나는 Swift에서 이와 같은 것을 할 수 없습니다. 다음과 같은 방법으로 변수 선언을 시도했습니다.

static var timesCalledA = 0
var static timesCalledB = 0
var timesCalledC: static Int = 0
var timesCalledD: Int static = 0

그러나 이것들은 모두 오류를 초래합니다.

  • 첫 번째는 "정적 속성은 유형에 대해서만 선언 할 수 있습니다"라고 불평합니다.
  • 두 번째 ( "예상 선언"불평 static하다) 및 "예상 된 패턴"(여기서, timesCalledB임)
  • 세 번째는 "행의 연속 명령문은 ';'(콜론과 사이의 공백 static) 및"예상 유형 "(여기서는 static)으로 구분되어야합니다.
  • 네 번째는 "행의 연속 문은 ';'( Int와 사이의 공백 static) 및"예상 선언 "(등호 아래) 으로 구분되어야합니다.

답변:


158

Swift는 클래스 / 구조체에 연결하지 않고 정적 변수를 지원한다고 생각하지 않습니다. 정적 변수로 개인 구조체를 선언하십시오.

func foo() -> Int {
    struct Holder {
        static var timesCalled = 0
    }
    Holder.timesCalled += 1
    return Holder.timesCalled
}

  7> foo()
$R0: Int = 1
  8> foo()
$R1: Int = 2
  9> foo()
$R2: Int = 3

그래, 나는 계속해서 조금 놀았고 이것은 기본적으로 내가 생각해 낸 정말 투박한 해결책이었습니다.
nhgrif 2014-08-18

17
충격을 받았지만, 이것에 의지해야해서 슬프다.
Tricertops

1
유형 속성과 메서드는 유형 (즉, Class, Struct 또는 Enum)에 속하며 함수에만 속할 수 없습니다. 유형 속성에 대한 Apple 문서 . @Tricertops. 이 문제를 해결하는 또 다른 방법은 "foo"함수를 클래스에 넣고 해당 클래스에 대한 유형 속성을 만들고 함수 내에서 사용하는 것입니다.
NSCoder

6
@NSCoder 그러나 struct Holder {…}여러 함수 내 에서 선언 할 수 있으며 충돌하지 않습니다. Swift는 static letstruct상용구 없이도 지원할 수 있습니다.
Tricertops

1
@Honey 미안하지만 더 업데이트 된 다른 답변을 찾을 수 없습니까?
Bryan Chen

23

또 다른 해결책

func makeIncrementerClosure() -> () -> Int {
    var timesCalled = 0
    func incrementer() -> Int {
        timesCalled += 1
        return timesCalled
    }
    return incrementer
}

let foo = makeIncrementerClosure()
foo()  // returns 1
foo()  // returns 2

3
이것은 일반적인 자바 스크립트 방식입니다
Bryan Chen

1
그러나 ba ()를 다시 호출하면 내부 함수는 첫 번째 호출에서 1을 반환합니다. 이것은 정적 변수와 다릅니다.
nhgrif 2014

2
이는 또한 여기에 애플의 문서로 진행됩니다 : developer.apple.com/library/ios/documentation/Swift/Conceptual/... 그것은 단지 "함수형 프로그래밍"과 라인을 유지하는 가장 좋은 솔루션이 될 것 같다,하지만 다른 해결책이 있습니다 잘. 그래도 이것은 받아 들여지는 대답이어야합니다.
datWooWoo

1
미안하지만 이것은 동일한 문제에 대해 더 많은 복잡성을 추가하는 추악한 해킹입니다. 너의 요점이 뭐야? 이 경우 간단한 클래스 속성을 선호합니다. @Brian Chen의 답변은 가장 가까운 답변입니다. 나는 그의 대답을 플립 플롭 종류의 해결책으로 사용합니다. Daniel은 Apple의 Swift 프로그래밍 규칙을 가장 잘 따르는 사람 일 것입니다.
AndaluZ 2015 년

1
나는 특히이 솔루션을 좋아했습니다. 이것은 함수 범위 내에서 정적 변수와 동일한 결과를 얻기 위해 고차 함수를 사용하는 완벽한 예입니다. 정적 함수 vars는 좋은 이유로 Swift에서 기본적으로 지원되지 않습니다. 프로그래밍의 자연스러운 진화입니다. 구식 방식으로 코딩하려면 해킹이 필요합니다. 제 생각에는 변수 캡처를 사용하는 대신 중첩 된 데이터 유형을 추가하면 코드 가독성이 감소합니다.
nstein 2016-07-25

18

Xcode 6.3이 포함 된 Swift 1.2는 이제 예상대로 정적을 지원합니다. Xcode 6.3 베타 릴리스 정보에서 :

이제 "정적"메서드와 속성이 클래스에서 허용됩니다 ( "클래스 최종"의 별칭으로). 이제 전역 저장소가 있고 처음 액세스 할 때 (전역 변수와 같이) 느리게 초기화되는 클래스에서 정적 저장된 속성을 선언 할 수 있습니다. 이제 프로토콜은 유형 요구 사항을 "클래스"요구 사항으로 선언하는 대신 "정적"요구 사항으로 선언합니다. (17198298)

함수는 (질문에서 묻는 것처럼) 정적 선언을 포함 할 수 없습니다. 대신 클래스 수준에서 선언해야합니다.

클래스 함수가 ​​필요하지 않더라도 클래스 (정적) 함수 내에서 증가하는 정적 속성을 보여주는 간단한 예 :

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

StaticThing.doSomething()
StaticThing.doSomething()
StaticThing.doSomething()

산출:

1
2
3

1
이 의미의 차이는 static애플 측에서 의도적 인 것일 수 있지만 변경을 요청하기 위해 버그 를 제출하는 것은 언제나 환영합니다 . C에서는 static제한 저장 변수 선언의 위치를 결정하는 동안, (항상 클래스 범위와 동일하지 않다) 소스 파일 범위에 변수를 어휘 범위 (개별 nested- VS 함수 내 VS 즉 글로벌 {}들). Swift에서 스토리지 범위는 항상 어휘 범위를 따르므로 함수에 어휘적이고 전역 스토리지가있는 변수를 가질 수 없습니다.
rickster

5
Daniel, 이것은 실제로 질문이 묻는 것과는 미묘하지만 (중요하게) 다릅니다. 그래도 대답에 감사드립니다. @rickster 나는 당신이 말하는 것을 이해하고 귀하의 의견 이이 질문에 대한 좋은 답변으로 확장 될 수 있다고 생각합니다.
nhgrif

@nhgrif 그래, 나는 이것이 특정 질문을 다루지 않는다고 대답했다. 저는 Swift 1.2의 변경 사항이이 사용 사례의 핵심 요구 사항을 해결한다고 생각했습니다 (확실히 Swift 1.2 이전보다 더 나은 이야기). 그러나 변수 범위를 함수로 지정하는 것이 중요한 것처럼 들립니다. 현재는 불가능합니다.
Daniel

CI의 @rickster는 정적이 항상 실제로 전역 적으로 저장된다고 생각합니다. 그래도 잘 모르겠습니다. 이것이 애플이 여기서 해결하려는 문제라고 생각합니다. 신속하게, 이제 항상 어휘 및 스토리지 범위가 클래스로 지정됩니다
BTRUE

@nhgrif 내 이전 의견과 함께 Daniel의 대답은 실제로 허용되는 대답이어야한다고 생각합니다. objc의 함수에서 정적 var를 어휘 적으로 선언 할 수 있지만 범위가 지정되지 않았기 때문에 정적 유형을 사용하는 것과 동일한 효과를 나타냅니다. 신속한 속성. 유일한 차이점은 신속한 선언 지점이 변수의 범위가 무엇인지에 대해 훨씬 더 설명적이고 오해의 소지가 없다는 것입니다.
BTRUE

0

또 다른 해결책

class Myclass {
    static var timesCalled = 0
    func foo() -> Int {
        Myclass.timesCalled += 1
        return Myclass.timesCalled
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.