7.2.5 InOut 매개변수

기본적으로 함수 내부에서 발생하는 사건은 함수 외부에 영향을 미칠 수 없습니다. 단순히 같은 값을 가질 뿐 둘은 단절된 객체이기 때문입니다. 예제를 보시겠습니다.

var cnt = 30

func autoIncrement(value: Int) -> Int {
    var value = value
    value += 1
    
    return value
}

print(autoIncrement(value: cnt)) // 함수 내부의 value 변수값 : 31
print(cnt) // 외부에서 정의된 cnt 변수값 : 30

왜 두 값이 차이가 날까요? 외부에서 입력한 인자값의 참조값이 직접 함수 내부로 전달되는 것이 아니라 그 값이 복사된 다음 전달되기 때문입니다. 즉 인자값으로 전달된 cnt 와 value 는 서로 다른 변수입니다.

하지만 함수에서도 내부에서 수정된 인자값이 외부까지 영향을 미칠 수 있는 방법이 존재합니다. 바로 inout 키워드입니다.

func foo(paramCount: inout Int) -> Int {
    paramCount += 1
    return paramCount
}
var count = 30
print(foo(paramCount: &count)) // 함수 내부의 paramCount 변수값: 31
print(count) // 외부에서 정의된 count 변수값: 31

함수를 호출하는 부분에서 count가 인자값으로 사용된 부분에 주소 추출 연산자인 &연산자가 붙어 있습니다. 이는 값이 아닌 주소가 전달되며 이 주소를 읽어 들이기 위해 함수에서는 매개변수에 inout 키워드가 추가된다고 보면 됩니다. 이처럼 주소를 전달하는 것을 프로그래밍 용어로 "참조에 의한 전달"이라고 하고, 기존처럼 값을 복사하여 전달하는 것을 "값에 의한 전달"이라고 합니다.

이처럼 주소를 직접 전달하는 참조에 의한 전달은 함수에서 inout키워드를 사용했을 때 적용되지만, 예외적으로 클래스(Class)로 구현된 인스턴스는 inout 키워드를 사용하지 않아도 항상 참조에 의해 전달됩니다. 따라서 함수 내부에서 값이 수정되면 원본 객체에도 영향을 미치므로 주의해야 합니다.

inout키워드가 붙은 매개변수는 함수 내부에서 직접 값을 수정할 수 있으므로 상수는 전달 대상이 될 수 없습니다. 같은 이유로 리터럴 역시 불가능하며 오직 변수만 사용할 수 있습니다.

// 상수는 inout 매개변수에 인자값으로 전달할 수 없음
let count1 = 30
foo(paramCount: &count1) // X

// 리터럴은 inout 매개변수에 인자값으로 전달할 수 없음
foo(paramCount: &30) // X

// 변수는 inout 매개변수에 인자값으로 전달할 수 있음
var value = 30
foo(paramCount: &value) // O 

Last updated