Swift Pass By Value 또는 Pass By Reference


100

저는 Swift를 처음 접했고 클래스가 참조로 전달되고 배열 / 문자열 등이 복사된다는 것을 읽었습니다.

참조에 의한 전달은 Objective-C 또는 Java에서 실제로 "a"참조를 전달하는 것과 동일한 방식입니까? 아니면 참조에 의한 적절한 전달입니까?


"참조에 의한 전달은 Objective-C 또는 Java에서와 동일한 방식입니까"Objective-C와 Java에는 참조에 의한 전달이 없습니다.
newacct 2014

2
예. 알아요. 당신은 참조로 통과하지 않습니다. 값으로 참조를 전달합니다. 대답 할 때 알고 있다고 생각했습니다.
gran_profaci

Java는 참조가 아닌 값으로 전달됩니다.
6rchid

답변:


167

스위프트의 사물 유형

규칙은 다음과 같습니다.

  • 클래스 인스턴스는 참조 유형 (즉, 당신의 클래스 인스턴스를 참조하여 효과적으로이다 포인터 )

  • 함수는 참조 유형입니다.

  • 그 밖의 모든 것은 값 유형입니다 . "기타 모든 것"은 단순히 구조체의 인스턴스와 열거 형의 인스턴스를 의미합니다. 그게 스위프트에있는 전부이기 때문입니다. 예를 들어 배열과 문자열은 구조체 인스턴스입니다. newacct가 지적한 것처럼 주소 를 사용 하고 가져옴 으로써 (함수 인수로) 이러한 것 중 하나에 대한 참조를 전달할 수 있습니다inout . 그러나 유형 자체는 가치 유형입니다.

참조 유형이 의미하는 것

참조 유형 객체는 실제로 다음과 같은 이유로 특별합니다.

  • 단순한 할당 또는 함수에 전달하면 동일한 객체에 대한 여러 참조가 생성 될 수 있습니다.

  • 객체에 대한 참조가 상수 ( let, 명시 적 또는 암시 적) 인 경우에도 객체 자체는 변경 가능합니다 .

  • 개체에 대한 변형은 개체에 대한 모든 참조에서 볼 수있는 것처럼 개체에 영향을줍니다.

위험 할 수 있으므로주의를 기울이십시오. 반면에 참조 유형을 전달하는 것은 포인터 만 복사 및 전달되기 때문에 명확하게 효율적입니다.

가치 유형이 의미하는 바

분명히 값 유형을 전달하는 것은 "안전하다"는 let의미이며 let참조 를 통해 구조체 인스턴스 또는 열거 형 인스턴스를 변경할 수 없습니다 . 다른 한편으로, 그 안전성은 가치의 별도 사본을 만들어 달성되는 것입니까? 값 유형을 전달하는 데 잠재적으로 비용이 많이 들지 않습니까?

글쎄, 예 그리고 아니오. 생각만큼 나쁘지 않습니다. Nate Cook이 말했듯이, 값 유형을 전달하는 것이 반드시 복사를 의미하는 것은 아닙니다 . 왜냐하면 let(명시 적 또는 묵시적) 불변성을 보장하므로 아무것도 복사 할 필요가 없기 때문입니다. 그리고 심지어로 통과 var참조하는 일이 의미하지는 않습니다 것입니다 그들은 단지 것을, 복사 할 수 있습니다 (돌연변이가 있기 때문에) 필요합니다. 이 문서는 특히 팬티를 뒤틀 지 말라고 조언합니다.


6
"클래스 인스턴스는 참조로 전달됩니다. 함수는 참조로 전달됩니다."아니요. 매개 변수가 inout유형에 관계없이 없을 때 값에 의한 전달 입니다. 참조에 의한 전달 여부는 유형과 직교합니다.
newacct 2014

4
@newacct 물론 엄격한 의미에서 당신 말이 맞습니다! 엄밀히 말하면 모든 것이 값으로 전달되지만 열거 형 인스턴스와 구조체 인스턴스는 값 유형 이고 클래스 인스턴스와 함수는 참조 유형 이라고 말해야합니다 . 예를 들어, developer.apple.com/swift/blog/?id=10 참조 -developer.apple.com/library/ios/documentation/Swift/Conceptual/… 도 참조하세요. 하지만 제가 말한 내용이 일반 내용과 일치한다고 생각합니다. 단어 의미의 의미.
매트

6
맞습니다. 값 유형 / 참조 유형은 값 또는 참조에 의해 전달 될 수 있고 참조 유형도 값 또는 참조로 전달 될 수 있기 때문에 값에 의한 전달 / 참조에 의한 전달과 혼동해서는 안됩니다.
newacct 2014

1
@newacct 매우 유용한 토론; 오해하지 않도록 요약을 다시 작성하고 있습니다.
매트

43

그것은되어 항상 패스에 의해 값 매개 변수가없는 경우 inout.

그것은되어 항상 패스에 의해 참조 매개 변수 인 경우 inout. 그러나 &이는 inout매개 변수에 전달할 때 인수에 연산자 를 명시 적으로 사용해야한다는 사실로 인해 다소 복잡 하므로 변수를 직접 전달하는 참조에 의한 전달의 기존 정의에 맞지 않을 수 있습니다.


3
Nate Cook의 답변과 결합 된이 답변은 "참조 유형"조차 명시 적으로 지정 하지 않는 한 (를 사용하여 ) 함수 범위 외부에서 수정 되지 않는다는 사실에 대해 더 명확했습니다 (C ++에서 제공 )inout
Gobe

10
inout실제로 참조로 전달되지는 않지만 copy-in copy-out 함수 호출 후 수정 된 값이 원래 인수에 할당되도록 보장합니다. 인 - 아웃 매개 변수
Dalija Prasnikar

모든 것이 가치에 의해 전달된다는 것은 사실이지만. 참조 유형 속성은 동일한 인스턴스에 대한 복사 참조로 함수 내에서 수정할 수 있습니다.
MrAn3

42

Swift의 모든 것은 기본적으로 "복사"에 의해 전달되므로 값 유형을 전달하면 값의 사본을 얻게되고 참조 유형을 전달하면 의미하는 모든 내용과 함께 참조의 사본을 얻게됩니다. (즉, 참조 사본은 여전히 ​​원래 참조와 동일한 인스턴스를 가리 킵니다.)

Swift는 많은 최적화를 수행하기 때문에 위의 "복사"주위에 겁을주는 인용문을 사용합니다. 가능하면 돌연변이 나 돌연변이 가능성이있을 때까지 복사하지 않습니다. 매개 변수는 기본적으로 변경 불가능하므로 대부분의 경우 실제로 복사가 발생하지 않습니다.


예를 들어 매개 변수가 동일한 참조를 가리 키기 때문에 복사본 (값에 의한 전달) 인 경우에도 함수 내에서 인스턴스 속성을 수정할 수 있음을 명확히했기 때문에 이것이 가장 좋은 대답입니다.
MrAn3

9

다음은 참조로 전달하기위한 작은 코드 샘플입니다. 강력한 이유가없는 한 이렇게하지 마십시오.

func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
    value1 = "my great computation 1";
    value2 = 123456;
}

이렇게 불러

var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);

왜 이것을 피해야합니까?
Brainless

1
@Brainless는 코드에 불필요한 복잡성을 추가하기 때문입니다. 매개 변수를 가져 와서 단일 결과를 반환하는 것이 가장 좋습니다. 이를 수행해야하는 경우 일반적으로 설계 불량을 알립니다. 또 다른 방법은 전달 된 참조 변수의 숨겨진 부작용이 호출자에게 투명하지 않다는 것입니다.
Chris Amelinckx

이것은 참조로 전달되지 않습니다. inout복사 입력, 복사 출력 연산자입니다. 먼저 객체에 복사 한 다음 함수가 반환 된 후 원래 객체를 덮어 씁니다. 동일하게 보일 수 있지만 미묘한 차이가 있습니다.
Hannes Hertach

7

애플 스위프트 개발자 블로그라는 게시물이 값 및 참조 유형 이 매우 주제에 대한 명확하고 자세한 설명을 제공합니다.

인용하려면 :

Swift의 유형은 첫 번째, "값 유형"중 하나에 속합니다. 여기서 각 인스턴스는 일반적으로 struct, enum 또는 tuple로 정의되는 고유 한 데이터 사본을 유지합니다. 두 번째는 인스턴스가 데이터의 단일 사본을 공유하는 "참조 유형"이며 유형은 일반적으로 클래스로 정의됩니다.

Swift 블로그 게시물은 예제를 통해 차이점을 계속 설명하고 다른 하나를 사용할 때를 제안합니다.


1
이것은 질문에 대한 답이 아닙니다. 질문은 값 유형 대 참조 유형과 완전히 직교하는 값에 의한 전달 대 참조에 의한 전달에 관한 것입니다.
Jörg W Mittag 2016 년

2

클래스는 참조로 전달되고 다른 클래스는 기본적으로 값으로 전달됩니다. inout키워드 를 사용하여 참조로 전달할 수 있습니다 .


이것은 올바르지 않습니다. inout복사 입력, 복사 출력 연산자입니다. 먼저 객체에 복사 한 다음 함수가 반환 된 후 원래 객체를 덮어 씁니다. 동일하게 보일 수 있지만 미묘한 차이가 있습니다.
Hannes Hertach

2

inout을 + =와 같은 중위 연산자와 함께 사용하면 & address 기호를 무시할 수 있습니다. 컴파일러가 참조로 통과한다고 가정합니까?

extension Dictionary {
    static func += (left: inout Dictionary, right: Dictionary) {
        for (key, value) in right {
            left[key] = value
        }
    }
}

origDictionary + = newDictionaryToAdd

그리고 멋지게이 사전 'add'는 원래 참조에도 하나의 쓰기 만 수행하므로 잠금에 적합합니다!


2

클래스와 구조

구조와 클래스의 가장 중요한 차이점 중 하나는 구조가 코드에서 전달 될 때 항상 복사되지만 클래스는 참조로 전달된다는 것입니다.

폐쇄

클래스 인스턴스의 속성에 클로저를 할당하고 클로저가 인스턴스 또는 해당 멤버를 참조하여 해당 인스턴스를 캡처하면 클로저와 인스턴스 사이에 강력한 참조주기가 생성됩니다. Swift는 캡처 목록을 사용하여 이러한 강력한 참조주기를 끊습니다.

ARC (Automatic Reference Counting)

참조 계산은 클래스 인스턴스에만 적용됩니다. 구조와 열거는 참조 유형이 아니라 값 유형이며 참조로 저장 및 전달되지 않습니다.

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