[Swift] in-out 파라미터의 개념과 동작 과정

·2024년 7월 9일
0

Swift 문법

목록 보기
16/16

in-out 파라미터

함수 파라미터는 기본적으로 상수이다.
함수 본문 내에서 파라미터 값을 변경하려고 하면 에러 발생

따라서 함수 파라미터 값을 변경하고, 함수 호출이 종료된 후에도 그 값을 유지하고 싶다면 inout 파라미터를 사용해 보자.

  • 파라미터 타입 전에 inout 키워드를 작성해 준다.
  • 수정 가능함을 알리기 위해 인수로 전달할 때는 & 붙여주기
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let tmpA = a
    a = b
    b = tmpA
}

var a = 5
var b = 3
swapTwoInts(&a, &b)

print(a, b) // 3 5

참고로 Swift에는 swap 함수가 이미 내장되어 있긴 하다


in-out 파라미터의 전달 과정

  1. 함수가 호출될 때 인수의 값은 복사됨
  2. 함수 본문 내에서 복사본이 수정됨
  3. 함수가 반환될 때 복사본의 값은 기존 인수에 할당됨

사실 call by value라는 의미다.
(copy-in copy-out이라고도 할 수 있다.
함수에 전달된 인수의 값을 복사하고 copy-in,
함수가 반환될 때 변경된 값을 원래 변수에 다시 복사하여 반영 copy-out)

var number: Int = 2 {
    willSet { // 새 값이 저장되기 직전 호출
        print("newValue:", newValue)
    }

    didSet { // 새 값이 저장된 직후 호출
        print("oldValue:", oldValue)
    }
}

func inoutTest(num: inout Int) {
    print("inoutTest1:", number)
    num = 5
    print("inoutTest2:", number)
    num = 7
    print("inoutTest3:", number)
}

inoutTest(num: &number)
print("number:", number) // 7

/*
 inoutTest1: 2
 inoutTest2: 2
 inoutTest3: 2
 newValue: 7
 oldValue: 2
 number: 7
*/

해당 코드를 보면, number 출력은 항상 2로 동일함을 알 수 있고,
함수 종료 후 number 출력 시엔 값이 변경된다.


inout 최적화

하지만 실제 메모리 주소에 저장된 값이 inout 파라미터로 전달될 경우, 컴파일러는 최적화를 적용할 수 있다.

call by reference와 동일한 원리로 메모리 위치가 함수 본문 내부와 외부에서 사용되어 copy-in copy-out과 같은 효과를 낼 수 있지만 오버헤드는 줄일 수 있다는 것.

하지만 우리가 코드를 작성할 때는 이러한 최적화에 의존하지 않고 또는 신경쓰지 않고,

copy-in copy-out으로 작성하여 최적화를 하지 않고도 잘 동작하도록 해야 한다.

최적화는 컴파일러의 몫……………………………..

.

.

.

아무리 해석해 보고 이해해 보고 찾아봐도 이렇게밖에 이해가 안 된다…
도와주십시오…


inout 더 알아보기

  • in-out 파라미터의 인수로는 당연히 변수만 전달할 수 있다. 상수는 수정할 수 없기 때문.
  • in-out 파라미터는 기본값을 가질 수 없고, 가변 파라미터는 inout 으로 표기할 수 없음

  • inout 인수로 전달된 값은 접근할 수 없다

    • 값에 대한 동시 접근 → 메모리 독점성 위반
    var property = 3
    
    func inoutTest(_ p: inout Int) {
        p += property
    }
    
    // 🚨 error
    inoutTest(&property)
  • 여러 개의 inout 파라미터에 동일한 값을 전달할 수 없다

    • 위와 마찬가지로 값에 대한 동시 접근이고, 메모리 독점성을 위반한다
  • in-out 파라미터를 캡처하는 클로저 또는 중첩 함수는 non-escaping이어야 함

    • inout 파라미터는 함수가 실행될 때만 유효하므로 함수가 종료된 후 실행되는 escaping 클로저는 동작 방식과 맞지 않다.
  • 캡처리스트를 사용하여 inout 파라미터가 변경되지 않게 할 수 있다.

    func someFunction(a: inout Int) -> () -> Int {
        return { [a] in return a + 1 }
    }

0개의 댓글

관련 채용 정보