더북(TheBook)

13.6.1 유사 참조 구조체의 규칙

무엇을 할 수 있는지 이야기하기에 앞서, RefLikeStruct로 무엇을 할 수 없는지 먼저 간략히 살펴보자.

RefLikeStruct를 유사 참조 구조체가 아닌 다른 타입의 필드로는 사용할 수 없다. 일반 구조체의 경우 박싱을 이용하거나 클래스 내에 구조체 필드를 두면 힙에 구조체를 둘 수 있다. 유사 참조 구조체 내에 RefLikeStruct를 두더라도 정적 필드로는 구성할 수 없고, 반드시 인스턴스 필드로만 사용할 수 있다.

RefLikeStruct를 박싱할 수 없다. 박싱은 힙에 객체를 생성하기 위해 설계된 방식이다. 이는 원하는 바가 아니다.

RefLikeStruct를 제네릭 메서드나 제네릭 타입의 타입 인수로 사용할 수 없으며(명시적으로 지정할 수도 없고 타입 추론을 이용할 수도 없다.), 제네릭 유사 참조 구조체 타입의 타입 인수로도 사용할 수 없다. 제네릭 타입 인수를 사용하는 제네릭 코드는 List<T>에서처럼 힙에 값을 둘 수 있다.

RefLikeStruct[]를 사용할 수 없으며, typeof 연산자의 피연산자로 배열과 유사한 형태를 사용할 수 없다.

RefLikeStruct 타입의 지역 변수는 컴파일러가 해당 변수를 캡처해야 하는 곳에서는 사용할 수 없다. 이러한 예로는 다음과 같은 경우가 있다.

• 비동기 메서드 : 비동기 메서드 내에서 RefLikeStruct 타입의 지역 변수를 선언하고 await 표현식 사이에서는 사용할 수 있지만, 여러 await 표현식을 가로질러 사용할 수는 없다(await 표현식 이전에 선언하거나 await 표현식 다음에 사용하는 것도 무방하다). 비동기 메서드의 매개변수로는 유사 참조 구조체 타입을 사용할 수 없다.

• 이터레이터 블록 : ‘두 개의 yield 표현식 사이에서만 RefLikeStruct를 사용할 수 있다’는 규칙이 있다. 이터레이터 블록의 매개변수로는 유사 참조 구조체 타입을 사용할 수 없다.

• 지역 메서드, LINQ 쿼리 표현식, 익명 메서드, 람다 표현식 내에서 캡처되는 지역 변수

추가적으로, 아주 복잡한 규칙3이기는 하지만 유사 참조 타입의 참조 지역 변수는 사용할 수 있다는 규칙도 있다. 이런 부분에 대해서는 그냥 컴파일러에 의지하기 바란다. 만약 유사 참조 구조체로 인해 컴파일이 제대로 되지 않는다면, 더 이상 스택에 존재하지 않는 값으로 작업하려 했다고 생각해도 좋다. 스택에 값을 유지하기 위한 일련의 규칙들을 준수한다면, 유사 참조 구조체의 전형적인 사용 예라고 할 수 있는 Span<T>를 사용할 수 있다.

 

 


3 정말 이해하기 난해한 규칙들이다. 이 기능을 통해 제공하려는 목표는 충분히 이해하고 있다고 생각하지만, 이 기능 때문에 무엇인가 잘못되는 것을 피하기 위해서 세부적으로 마련해 둔 규칙을 하나하나 살펴보는 것은 내 관심 수준을 벗어난다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.