복사 및 업데이트 레코드 식
복사 및 업데이트 레코드 식 (Copy and Update Record Expressions)
오늘은 F#의 **복사 및 업데이트 레코드 식(Copy and Update Record Expression)**에 대해 알아볼게요. 이 식은 기존 레코드를 그대로 복사하면서, 지정한 필드만 바꿔서 새로운 레코드를 만들어 주는 표현이에요. 불변(immutable) 데이터를 다루는 F#에서 아주 자주 쓰이는 패턴이니 잘 익혀두면 좋아요.
본문
복사 및 업데이트 레코드 식은 기존 레코드를 복사하고, 지정된 필드를 업데이트한 뒤, 그 결과 레코드를 반환하는 식입니다.
구문 (Syntax)
{ record-name with
updated-labels }
{| anonymous-record-name with
updated-labels |}
설명 (Remarks)
레코드와 익명 레코드는 기본적으로 **불변(immutable)**이라서, 이미 만들어진 레코드를 직접 수정할 수 없어요. 그래서 업데이트된 레코드를 만들려면 모든 필드를 처음부터 다시 지정해야 하는 번거로움이 있었죠. 이 불편함을 해결하기 위한 게 바로 복사 및 업데이트 식이에요. 이 식은 기존 레코드를 받아서, 같은 타입의 새 레코드를 만드는데, 지정한 필드는 식에서 주어진 값으로 채우고 나머지 필드는 기존 레코드에서 그대로 가져옵니다.
기존 레코드를 복사하면서 일부 필드 값을 바꿔야 할 때 특히 유용해요.
예를 들어, 아래처럼 새 레코드를 하나 만들었다고 해볼게요.
let myRecord2 =
{ MyRecord.X = 1
MyRecord.Y = 2
MyRecord.Z = 3 }
이 레코드에서 두 필드만 바꾸고 싶다면, 복사 및 업데이트 레코드 식을 이렇게 쓰면 됩니다:
let myRecord3 = { myRecord2 with Y = 100; Z = 2 }
중첩 레코드 복사 및 업데이트 (Nested Record Copy and Update)
F# 7.0 이상에서는 복사 및 업데이트 식이 중첩된 레코드 필드의 업데이트를 지원하도록 확장되었어요. 이 기능 덕분에 깊게 중첩된 레코드를 다룰 때 훨씬 간결한 구문을 쓸 수 있게 됐습니다.
다음 예시를 볼까요?
이전 (Before)
type SteeringWheel = { Type: string }
type CarInterior = { Steering: SteeringWheel; Seats: int }
type Car = { Interior: CarInterior; ExteriorColor: string option }
let beforeThisFeature x =
{ x with Interior = { x.Interior with
Steering = {x.Interior.Steering with Type = "yoke"}
Seats = 5
}
}
이후 (After)
새 기능을 쓰면 **점 표기법(dot-notation)**으로 중첩 필드에 직접 접근해서 바로 업데이트할 수 있어요:
let withTheFeature x =
{ x with Interior.Steering.Type = "yoke"; Interior.Seats = 5 }
이 구문은 여러 개의 with 식을 써야 했던 번거로움을 없애줍니다. 대신 중첩된 필드에 직접 업데이트를 지정하면서도, 같은 식 안에서 서로 다른 중첩 깊이의 여러 필드를 한 번에 업데이트할 수 있어요.
익명 레코드 (Anonymous Records)
이런 구문 확장은 익명 레코드에서도 똑같이 동작해요. 게다가 이 구문을 쓰면 일반 레코드를 익명 레코드로 복사·업데이트하면서, 그 과정에서 새 필드를 추가하는 것도 가능합니다:
let updatedRecord =
{| originalRecord with
Interior.Seats = 4;
Price = 35000 |}
이러한 유연성 덕분에, 일반 레코드를 다루든 익명 레코드를 다루든 동일하게 간결한 구문을 사용할 수 있어요.