ReScript in Korean

언박싱

원문

리스크립트에서 단일 페이로드로 이루어진 배리언트와 단일 필드로 이루어진 레코드를 살펴봅시다.

type name = Name(string)
let studentName = Name("Joe")
type greeting = {message: string}
let hi = {message: "hello!"}
var studentName = /* Name */ {
_0: 'Joe',
};
var hi = {
message: 'hello!',
};

자바스크립트 출력을 보면, studentName 또는 hi가 자바스크립트 객체에 포함된 것을 볼 수 있습니다. (자세한 내용은 배리언트의 자바스크립트 결과물레코드의 자바스크립트 결과물을 참고하세요)

성능이 중요하거나 간혹 특수한 자바스크립트 인터롭이 필요한 상황에서는 리스크립트가 제공하는 언랩(혹은 언박스) 기능을 사용할 수 있습니다. 언랩은 단일 필드 레코드 혹은 단일 페이로드-단일 생성자 배리언트가 JS로 변환될 때, 해당 객체의 래퍼를 벗겨냅니다. 타입 선언 위에 @unboxed라고 달면 됩니다.

@unboxed
type name = Name(string)
let studentName = Name("Joe")
@unboxed
type greeting = {message: string}
let hi = {message: "hello!"}
var studentName = 'Joe';
var hi = 'hello!';

변환 결과는 깔끔합니다.

사용하기

왜 싱글 페이로드를 가진 배리언트 또는 레코드가 필요할까요? 왜 그냥 페이로드를 넘기지 않을까요? 아래에서 배리언트의 사용 예를 알아보겠습니다.

아래와 같이 로컬 좌표계와 월드 좌표계를 쓰는 게임이 있습니다.

type coordinates = {x: float, y: float}
let renderDot = (coordinates) => {
Js.log3("Pretend to draw at:", coordinates.x, coordinates.y)
}
let toWorldCoordinates = (localCoordinates) => {
{
x: localCoordinates.x +. 10.,
y: localCoordinates.x +. 20.,
}
}
let playerLocalCoordinates = {x: 20.5, y: 30.5}
renderDot(playerLocalCoordinates)
function renderDot(coordinates) {
console.log('Pretend to draw at:', coordinates.x, coordinates.y);
}
function toWorldCoordinates(localCoordinates) {
return {
x: localCoordinates.x + 10,
y: localCoordinates.x + 20,
};
}
var playerLocalCoordinates = {
x: 20.5,
y: 30.5,
};
renderDot(playerLocalCoordinates);

이런, 뭔가 잘못되었습니다. renderDot은 전역 좌표를 기준으로 렌더링하는데 인자로 로컬 좌표가 전달됐습니다. 이제 코드를 수정해서 잘못된 좌표 타입이 전달되지 못하게 막아봅시다.

type coordinates = {x: float, y: float}
@unboxed type localCoordinates = Local(coordinates)
@unboxed type worldCoordinates = World(coordinates)
let renderDot = (World(coordinates)) => {
Js.log3("Pretend to draw at:", coordinates.x, coordinates.y)
}
let toWorldCoordinates = (Local(coordinates)) => {
World({
x: coordinates.x +. 10.,
y: coordinates.x +. 20.,
})
}
let playerLocalCoordinates = Local({x: 20.5, y: 30.5})
/* 이제 이렇게 호출하면 오류가 발생합니다! */
/* renderDot(playerLocalCoordinates) */
/* 대산 이렇게 사용하도록 강제합니다. */
renderDot(playerLocalCoordinates->toWorldCoordinates)
function renderDot(coordinates) {
console.log('Pretend to draw at:', coordinates.x, coordinates.y);
}
function toWorldCoordinates(coordinates) {
return {
x: coordinates.x + 10,
y: coordinates.x + 20,
};
}
var playerLocalCoordinates = {
x: 20.5,
y: 30.5,
};
renderDot(toWorldCoordinates(playerLocalCoordinates));

이제 renderDotworldCoordinates만을 입력으로 받습니다. 배리언트 타입으로 구분 + 인자 구조분해를 써서 더 안전한 코드를 만들었습니다. 성능 저하 없이요. unboxed 속성 덕분에 배리언트 래퍼 없이 깔끔하게 JS 코드로 컴파일됐습니다. 결과를 살펴보세요.