이번 포스트에서는 Swift의 inout 매개변수에 대해서 알아보도록 하겠습니다.

  • inout 매개변수란?
    Swift에서 함수와 메소드의 매개변수는 기본적으로 상수(Constant)로 전달이 되고, 해당 값을 직접 수정할 수 없습니다. 수정을 하려면 내부에서 별도의 지역변수를 선언해서 대입하는 과정이 필요합니다. 그렇게 해도, 변화된 값은 그 함수를 벗어나면 그대로 사라집니다.

    var a = 10
    
    func increment(_ num: Int) {
        var num = num
        num+=1
    }
    
    increment(a)
    
    print(a) // 10, 값 변화 없음
    

    inout은 이렇게 함수 내에서의 변화를 반환 값 이외의 방법으로 전달하는 방법입니다.

    var a = 10
    
    func increment(_ num: inout Int) {
        num+=1
    }
    
    increment(&a) // inout 매개변수에 값을 넘길때에는 &표시를 붙여야 합니다.
    
    print(a) // 11, 값 변화 있음
    

    inout은 값을 변화시키겠다는 선언으로 볼 수 있습니다. 따라서 상수나 리터럴을 넘길 수는 없습니다. 또한 가변 인자도 inout을 적용할 수 없습니다.

  • inout의 원리
    inout 매개변수는 다음과정을 거칩니다.

    1. 함수가 호출되면, 매개변수로 넘겨진 변수가 복사됩니다.

    2. 함수 몸체에서, 복사했던 값을 변화시킵니다.

    3. 함수가 반환될 때, 이 변화된 값을 원본 변수에 재할당합니다.

    이러한 방식을 copy-in copy-out 이라고 합니다. 실제로 inout은 copy-in copy-out의 줄임말로, 안으로 복사되고, 다시 바깥으로 복사된다는 뜻입니다.

    여기서 최적화 옵션을 키게 되면, Call by Reference로 동작을 하게 됩니다. 즉, 복사가 일어나지 않고, 해당 주소값을 그대로 사용합니다. 따라서 call by reference를 사용하고 싶으면 inout을 사용하면 됩니다. 다만 inout을 사용할 때는 메모리 접근에 주의해야 하는데, 이는 Swift의 메모리 안정성이라는 포스트에 관련내용을 다루었습니다.

    클로저에서도 inout을 적용할 수 있는데, 이 경우 클로저는 반드시 non-escaping이여야 합니다. 값을 변화시켜야 한다면, 캡쳐를 해야합니다. 다만 캡쳐는 상수기 때문에 copy-in copy-out을 직접 구현해야 합니다.


참고자료
Swift 언어 가이드 - Fuction