본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 22. 12:24

생성 AI 시대의 Rust 설계 ― 도메인 지식을 타입에 심기

요약

생성 AI가 코드를 대량으로 생성하는 시대에, AI가 생성한 코드가 도메인 규칙을 준수하도록 Rust의 타입 시스템을 활용하는 설계 방법을 소개합니다. 프리미티브 타입부터 Newtype, 상태 전이 모델링까지 단계별로 컴파일러를 가드레일로 사용하는 과정을 다룹니다.

핵심 포인트

  • AI 생성 코드의 신뢰성을 높이기 위해 도메인 규칙을 타입으로 명시해야 함
  • 컴파일러를 가드레일로 활용하여 규칙 위반 시 컴파일 에러를 유도함
  • 단순한 Primitive 타입을 넘어 Newtype과 상태 기반 타입 설계의 중요성 강조
  • 인간의 도메인 지식을 프로그램의 타입 시스템으로 옮기는 단계적 방법론 제시

AI를 통해 코드를 쉽고 대량으로 생성할 수 있게 되었습니다.

그 한편으로, 생성된 코드가 우리의 의도한 의미나 규칙을 정말로 준수하고 있는지 확인하는 것이 중요해지고 있습니다. AI는 주어진 사양이나 기존 코드로부터 도메인 모델 (Domain Model)을 어느 정도 이해할 수 있습니다. 하지만 세세한 규칙이 코드나 사양에 명시되어 있지 않다면, 추측에 의존할 수밖에 없습니다.

여기서 유효한 방법이 중요한 도메인 규칙을 타입 (Type)으로 표현하고, 컴파일러 (Compiler)를 가드레일 (Guardrail)로 이용하는 것입니다.

타입을 통해 규칙을 표현하면, "규칙에 위반하는 코드를 생성해도 컴파일을 통과할 수 없는" 설계를 할 수 있습니다. 이때 타입으로 지킬 수 있는 것은 타입으로 표현한 범위뿐입니다. 그럼에도 중요한 규칙을 인간의 기억이나 주의력에만 맡겨두는 것이 아니라, 컴파일러가 검사할 수 있는 형태로 옮기는 것에는 큰 의미가 있습니다.

이 기사에서는 그 과정을 간단한 예를 사용하여 단계적으로 살펴보겠습니다.

다음과 같은 상황을 상상해 보세요.

1000엔이 바닥에 떨어져 있고,
아직 아무도 줍지 않았다

본래라면 그대로 파출소에 가져다주고 싶지만, 그 전에 잠시 시간을 내어 이 상황을 단계적으로 타입으로 변신시켜 보겠습니다.

    1. 프리미티브 타입 (Primitive Type)으로 표현하기
    1. 튜플 (Tuple)로 만들어 관계를 표현하기
    1. 구조체 (Struct)로 만들어 개념을 표현하기
    1. Newtype으로 값의 의미를 타입으로 만들기
    1. bool은 편리하지만 상태 전이가 느슨하다
    1. 상태를 값이 아닌 타입으로 만들기
    1. 상태 전이를 메서드 (Method)의 타입으로 표현하기
    1. 허용되지 않는 조작은 컴파일 에러 (Compile Error)로 만들기
    1. 인간 측의 의미가 프로그램 측으로 옮겨가는 과정
  • 요약
  • PS

처음에는 "금액"과 "돈을 주웠는지 여부"를 별개의 값으로 표현합니다.

let money: u32 = 1000;
let picked: bool = false;

인간은 이 코드를 다음과 같이 해석할 수 있습니다.

money는 금액을 나타낸다 -
1000은 1000엔을 나타낸다 -
picked는 주웠는지 여부를 나타낸다 -
false는 아직 줍지 않았음을 나타낸다

하지만 컴파일러가 파악하고 있는 것은 각각의 타입뿐입니다.

money: u32
picked: bool

컴파일러에게 money는 부호 없는 정수 (Unsigned Integer)이며, picked는 불리언 (Boolean)입니다.

1000이라는 값에 대해서도 "1000엔"이 아니라 단순히 u32 타입의 정수로 취급합니다.

나아가 다음과 같은 관계도 컴파일러는 알지 못합니다.

moneypicked는 한 쌍의 데이터이다 -
pickedmoney의 상태를 나타낸다 -
money의 단위는 엔(円)이다

이 시점에서는 다음과 같은 상태 전이 규칙도 인간 측에만 존재합니다.

줍지 않은 돈 ──줍는다──▶ 주운 돈

더 구체적으로는 다음과 같은 규칙이 있습니다.

줍지 않은 돈은 주운 상태로 전이될 수 있다

주운 상태에서 줍지 않은 상태로는 돌아갈 수 없다

주운 돈을 다시 줍는 것은 할 수 없다

이 단계에서 프로그램 측에 있는 것은 u32bool이라는 범용 데이터뿐입니다.

돈이라는 것, 엔이라는 것, 두 가지가 관계되어 있다는 것, 상태 전이는 인간 측의 해석에 의존하고 있습니다.

다음으로 금액과 상태를 튜플 (Tuple)로 만듭니다.

let money: (u32, bool) = (1000, false);

이로써 컴파일러는 "u32bool이 한 쌍의 데이터이다"라는 것을 확인할 수 있게 됩니다.

(u32, bool)

별개의 변수로 표현했을 때는 금액과 상태가 항상 함께 다뤄진다는 보장이 없었습니다. 하지만 튜플로 만듦으로써, 적어도 두 값이 하나의 덩어리이다라는 관계는 프로그램 측으로 옮겨졌습니다.

다만, (u32, bool)이라는 타입만 보고는 그 덩어리가 무엇을 의미하는지는 알 수 없습니다.

같은 타입은 다른 상황에서 다음과 같이 해석될 수도 있습니다.

(나이, 유효한지 여부)
(재고 수, 공개되어 있는지 여부)
(점수, 합격했는지 여부)

쌍에 이름이 없기 때문에, u32bool이라는 두 명의 조합이 항상 함께 있을 뿐, 그것이 무엇인지는 여전히 인간 측이 해석하고 있습니다.

이 단계에서는 다음의 의미를 인간이 지키고 있습니다.

첫 번째
u32

는 엔(yen)을 나타낸다 -
두 번째

bool

은 집어든 상태를 나타낸다 -
이 조합 전체는 돈을 나타낸다

허가된 상태 전이가 존재한다

다음으로, 돈을 Money 구조체로 정의합니다.

struct Money {
  yen: u32,
  picked: bool,
  ...
}

값은 다음과 같이 만듭니다.

let money = Money {
  yen: 1000,
  picked: false,
  ...
};

여기서 프로그램 측에 Money라는 새로운 타입이 생겨납니다.

Money

Money는 단순한 u32도, bool도, (u32, bool)도 아닙니다.

이것들과는 별개로, 이름을 가진 타입으로서 구별됩니다.

또한 필드에도 이름이 붙음으로써, 튜플(tuple)보다 역할이 명확해졌습니다.

money.yen
money.picked

이로 인해 다음과 같은 구조가 코드상에 나타납니다.

Money는 다른 타입과 구별되는 하나의 개념이다 -
Money는 수치로서 yen을 가진다 -
Money는 상태로서 picked를 가진다 -
yenpicked는 하나의 데이터로 묶여 있다

컴파일러는 Money를 다른 타입과 구별하며, Money로 정의된 조작만을 허용할 수 있습니다.

새로운 타입을 명명하면, 도메인 상의 개념을 다른 개념으로부터 구별할 수 있게 됩니다.

구조체를 통해 "이 데이터 전체가 돈이다"라는 의미가 코드상에 나타났습니다.

하지만 한 단계 안쪽을 들여다보면, 아직 개선할 수 있는 점이 있습니다.

구조체로 만듦으로써 데이터 전체를 Money라는 개념으로 구별할 수 있게 되었습니다.

하지만 yen 필드의 타입 자체는 여전히 u32입니다.

struct Money {
  yen: u32,
  picked: bool,
  ...
}

u32는 부호 없는 정수(unsigned integer)임을 나타냅니다.

그 정수가 엔(yen)인지, 나이인지, 개수인지까지는 나타내지 않습니다.

예를 들어, 다음 값들은 모두 동일한 u32 타입입니다.

let yen: u32 = 1000;
let age: u32 = 20;
let item_count: u32 = 5;

인간에게는 각각 다음과 같이 다른 의미를 갖습니다.

1000엔
20세
5개

하지만 컴파일러 입장에서 보면 모두 같은 타입의 정수입니다.

그래서 엔(yen)을 나타내는 새로운 타입을 정의합니다.

struct Yen(u32);

그리고 Moneyu32가 아닌 Yen을 갖도록 변경합니다.

struct Money {
  amount: Yen,
  picked: bool,
  ...
}

이와 같이 기존 타입을 하나의 필드로 감싸서 새로운 타입으로 다루는 방법은 일반적으로 **뉴타입 패턴 (Newtype pattern)**이라고 불립니다.

Rust By Example에서도 뉴타입은 프로그램에 올바른 종류의 값이 전달되었음을 컴파일 타임에 보장하기 위한 방법으로 설명되어 있습니다.

예를 들어, 엔(yen)과 나이를 각각 별개의 타입으로 정의합니다.

struct Yen(u32);
struct Age(u32);

둘 다 내부에는 u32를 가지고 있습니다.

하지만 YenAge는 컴파일러에게 서로 다른 타입입니다.

struct Money {
  amount: Yen,
  picked: bool,
  ...
}

new에 전달할 수 있는 것은 Yen뿐입니다.

let amount = Yen(1000);
let money = Money::new(amount);

반면, Age는 전달할 수 없습니다.

let age = Age(20);
// 컴파일 에러
let money = Money::new(age);

AgeYen의 내부가 모두 u32라 하더라도, 타입으로서는 별개이기 때문입니다.

Age를 전달하면 인자가 일치하지 않아 다음과 같은 에러가 발생할 것입니다.

expected `Yen`, found `Age`

이를 통해 나이, 재고 수, 개수 등 다른 의미를 가진 u32를 금액으로 잘못 전달하는 것을 방지하기 쉬워집니다.

구조체 Money

는, 다음의 의미를 타입으로 만들었습니다.

이 데이터 전체는 돈이다

Newtype인 Yen

은, 구조체 내부에 있는 정수에 대해 다음의 의미를 타입으로 만들었습니다.

이 정수는 엔(Yen)이다

타입의 변화로 보면 다음과 같습니다.

u32
│
│ 엔(Yen)이라는 의미를 부여
...

다만, Yen(u32)로 감싸는 것만으로는 금액으로서 유효한 값의 범위까지는 보장되지 않습니다.

예를 들어, 다음과 같은 규칙이 있을 수 있습니다.

0엔을 허용할 것인가

금액의 상한은 얼마인가

특정 단위로만 다룰 수 있는가

그러한 규칙도 지키게 하고 싶다면, 내부의 값을 외부에서 직접 구축할 수 없도록 하고, 검증된 값만을 반환하는 생성자(Constructor)를 마련할 수 있습니다.

struct Yen(u32);
impl Yen {
    fn new(value: u32) -> Option<Self> {
        ...
    }
}

Newtype이 우선적으로 구분하는 것은 값의 크기가 아니라, 그 값이 무엇을 의미하는가입니다.

여기까지를 통해 데이터 전체의 개념과 그 내부에 있는 금액의 의미는 타입으로 표현할 수 있었습니다.

다음은 "주워졌는지 여부"라는 상태에 대해 생각해보겠습니다.

현재의 Money는 다음과 같은 구조체입니다.

struct Money {
    amount: Yen,
    picked: bool,
    ...
}

이 구조체에서는 상태가 bool로 표현되어 있습니다.

필드를 직접 변경할 수 있는 설계라면 다음과 같은 조작이 가능합니다.

let mut money = Money {
    amount: Yen(1000),
    picked: false,
    ...
};

프로그램상에서는 단순히 bool 값을 전환하고 있습니다.

하지만 인간이 표현하고 싶은 것은 자유로운 진위값(Boolean)의 변경이 아닙니다.

표현하고 싶은 것은 다음과 같은 일방향 상태 전이(State Transition)입니다.

줍지 않은 돈 ──줍는다──▶ 주운 돈

각 변경을 도메인상의 의미와 대응시키면 다음과 같습니다.

false → true (올바름)
아직 줍지 않은 것을 줍는다

true → false (올바르지 않음)
...

이러한 상태 전이 규칙을 bool에게만 맡기기에는 짐이 너무 무겁습니다.

물론 필드를 비공개(Private)로 설정하여 적절한 메서드를 통해서만 상태를 변경할 수 있도록 하면, 직접적인 쓰기(Write)는 방지할 수 있습니다.

impl Money {
    fn pick(mut self) -> Self {
        self.picked = true;
        ...
    }
}

나아가 메서드 내부에서 현재 상태를 검사하여, 이미 주워진 상태라면 에러를 반환할 수도 있습니다.

impl Money {
    fn pick(mut self) -> Result<Self, &'static str> {
        if self.picked {
            ...
        }
    }
}

이 설계로도 실행 시(Runtime)에 규칙을 지키게 할 수는 있습니다.

하지만 주워졌는지 여부에 대한 정보는 Money 내부의 값으로서 유지되고 있습니다.

줍기 전: Money
주운 후: Money

둘 다 타입으로서는 동일한 Money입니다.

따라서 함수 시그니처(Function Signature)만 보면 인자와 반환값이 같은 모습을 하고 있습니다.

fn pick(money: Money) -> Money

혹은 에러를 반환하는 설계라도 다음과 같습니다.

fn pick(money: Money) -> Result<Money, PickError>

이러한 시그니처만으로는 다음 사항들을 타입으로서 표현할 수 없습니다.

인자인 Money는 아직 줍지 않은 상태인가?

이미 주운 Money를 전달해도 되는가?

반환값인 Money는 반드시 주운 상태인가?

반환값에 대해 다시 한번 pick을 호출할 수 있는가?

구조체와 Newtype을 통해 데이터의 개념이나 값의 의미는 프로그램 측으로 옮겨갔습니다.

하지만 어떤 상태에서 어떤 조작이 허용되는가라는 규칙은 아직 값 레벨(Value Level)에 머물러 있습니다.

그래서 주워졌는지 여부를 bool이 아니라, 이름이 붙은 타입으로 표현합니다.

struct Unpicked;
struct Picked;

Unpicked는 아직 줍지 않은 상태를 나타냅니다.

Picked는 이미 주운 상태를 나타냅니다.

다음으로, Money에 상태를 나타내는 타입 파라미터 (Type Parameter) State를 추가합니다.

use std::marker::PhantomData;
struct Money<State> {
    amount: Yen,
    ...
}

Money는 실제 값으로서 Yen을 가지고 있습니다.

반면, 상태를 나타내는 State의 값 자체를 보유할 필요는 없습니다.

그래서 PhantomData<State>를 사용합니다.

PhantomData<T>는 제로 사이즈 타입 (Zero-sized type)이며, 실제로 T를 저장하고 있지 않더라도 해당 타입이 T와 결합되어 있음을 컴파일러에게 알리기 위해 사용할 수 있습니다. Rust 표준 라이브러리 문서에서도 PhantomData<T>를 추가하면, 실제로 값을 보유하고 있지 않더라도 타입이 T를 보유하고 있는 것처럼 취급된다고 설명되어 있습니다.

이 설계에서는 동일한 Money라도 상태에 따라 타입이 달라집니다.

Money<Unpicked>
Money<Picked>

인간 측의 의미와 대응시키면 다음과 같습니다.

Money<Unpicked> = 아직 줍지 않은 돈
Money<Picked> = 이미 주운 돈

이 둘은 컴파일러에게 서로 다른 타입입니다.

bool로 표현했을 때는 상태가 런타임 (Runtime)의 값이었습니다.

picked: bool

타입 파라미터를 사용하면, 상태 그 자체가 타입의 일부가 됩니다.

Money<Unpicked>
Money<Picked>

이를 통해 인간만이 구분하던 '줍기 전'과 '주운 후'를 컴파일러도 구분할 수 있게 됩니다.

이처럼 객체의 현재 상태에 관한 정보를 타입에 포함하는 설계를 일반적으로 **Typestate 패턴 (Typestate Pattern)**이라고 부릅니다. The Embedded Rust Book에서는 Typestate를 객체의 현재 상태에 관한 정보를 해당 객체의 타입으로 인코딩(Encoding)하는 개념으로 설명하고 있습니다.

다음으로, '줍기'라는 동작을 정의합니다.

주울 수 있는 것은 아직 줍지 않은 돈뿐입니다.

따라서 pick 메서드는 Money<Unpicked>에만 정의합니다.

impl Money<Unpicked> {
    fn new(amount: Yen) -> Self {
        Self {
            ...
        }
    }
}

new는 아직 줍지 않은 돈을 생성합니다.

fn new(amount: Yen) -> Money<Unpicked>

pick은 줍지 않은 돈을 받아, 이미 주운 돈을 반환합니다.

fn pick(self) -> Money<Picked>

타입 변환으로 보면 다음과 같습니다.

Money<Unpicked> → Money<Picked>

인간의 언어로 말하면 다음과 같은 스토리가 됩니다.

아직 줍지 않은 돈을 주우면,
주운 돈이 된다

여기서 인간 측의 스토리와 프로그램 측의 타입 변환이 대응합니다.

bool을 사용했을 때의 상태 변경은 값의 변경이었습니다.

false → true

Typestate로 표현한 경우에는 도메인 상 허용된 상태 전이 (State transition)가 타입 변환으로 나타납니다.

Money<Unpicked> → Money<Picked>

또한, pickself를 값으로 받습니다.

fn pick(self) -> Money<Picked>

&self&mut self가 아니라 self입니다.

따라서 pick은 호출 측의 Money<Unpicked> 소유권 (Ownership)을 가져갑니다. Rust에서는 값을 함수로 값 전달 (Pass by value)하면 소유권이 이동 (Move)되어, 원래의 소유자는 해당 값을 사용할 수 없게 됩니다.

let money = Money::<Unpicked>::new(Yen(1000));
let picked_money = money.pick();

moneypick으로 이동되었기 때문에 이후에는 사용할 수 없습니다.

대신, 주운 상태를 나타내는 Money<Picked>가 반환됩니다.

Money<Unpicked>가 소비되어
↓
Money<Picked>로 다시 태어납니다

조금 과장해서 말하자면, 타입 레벨의 윤회전생입니다.

이전 상태의 값은 사용할 수 없게 되고, 새로운 상태의 값만 남습니다.

줍지 않은 1000엔을 생성하고, 그것을 주워 보겠습니다.

let money = Money::<Unpicked>::new(Yen(1000));
let picked_money: Money<Picked> = money.pick();

picked_money는 이미 주워진 돈입니다.

여기서 다시 한번 pick을 호출해 보겠습니다.

let picked_again = picked_money.pick();

하지만 이 코드는 컴파일되지 않습니다.

pick 메서드는 Money<Unpicked>에만 정의되어 있기 때문입니다.

impl Money<Unpicked> {
    fn pick(self) -> Money<Picked> {
        // ...
    }
}

Money<Picked>에는 pick 메서드가 존재하지 않습니다.

즉, 다음의 도메인 규칙 (Domain Rule)이 타입에 의해 보호되고 있습니다.

주워진 돈을 다시 주울 수는 없다

이 규칙은 단순히 주석으로 주의 사항을 적어둔 것이 아닙니다.

// 이미 주워진 경우에는 pick을 호출하지 말 것

호출 측에서 주의하며 지켜야 하는 규칙도 아닙니다.

테스트에서 특정 케이스만 확인하는 규칙도 아닙니다.

Money<Picked>라는 타입에는 애초에 pick이라는 조작 자체가 마련되어 있지 않은 것입니다.

Money<Unpicked>
└── pick 가능
Money<Picked>
...

허용되지 않는 조작을 실행 시점에 실패하게 만드는 것이 아니라, 프로그램의 후보에서 제외하고 있습니다.

덧붙여, 이 보장을 외부 코드에 대해서도 성립시키려면 구조체의 필드를 비공개 (private)로 만들고, 정식 생성자(Constructor)와 상태 전이 (State Transition) 메서드만을 공개하는 것이 중요합니다.

필드를 자유롭게 수정하거나, 임의의 상태를 직접 구축할 수 있는 API를 공개하면 타입으로 설정한 입구를 우회할 수 있게 됩니다.

타입뿐만 아니라 모듈 경계 (Module Boundary)를 포함하여 설계해야 합니다.

지금까지의 변화를 정리합니다.

타입의 종류표현프로그램 측에서 검사할 수 있는 것주로 인간 측에서 지킬 것
프리미티브 타입 (Primitive Type)u32bool범용적인 타입으로서의 제약값의 의미, 두 값의 관계, 상태 전이
튜플 (Tuple)(u32, bool)두 값이 한 쌍이라는 것쌍 전체의 의미, 각 요소의 역할, 상태 전이
구조체 (Struct)Money { yen, picked }이름이 붙은 하나의 개념으로 구별하는 것필드 타입의 의미, 상태에 따라 허용되는 조작
뉴타입 (Newtype)Yen(u32)엔(Yen)과 나이, 개수 등 다른 정수를 구별하는 것유효한 금액의 범위, 그 규칙의 배경
타입스테이트 (Typestate)Money<Unpicked>Money<Picked>상태의 차이와 허용된 상태 전이해당 상태 전이를 채택하는 이유와 현실 세계의 배경

타입의 변화만을 나열하면 다음과 같습니다.

u32와 bool
│
│ 두 값을 한 쌍으로 만든다
...

처음에는 인간만이 다음의 스토리를 이해하고 있었습니다.

1000엔이 바닥에 떨어져 있다
아직 아무도 줍지 않았다
누군가 주우면, 주운 상태가 된다
...

최종적으로는 그 일부가 타입으로 표현되어 있습니다.

Yen
Money<Unpicked>
Money<Picked>
...

프로그램 측면에서 보면 이것은 타입의 변환입니다.

Money<Unpicked>에서
Money<Picked>로의 변환

인간 측면에서 보면 다음의 이야기입니다.

떨어져 있던 돈을 주웠다

이 두 가지가 대응함으로써, 컴파일러가 도메인 모델의 일부를 지키도록 만들 수 있습니다.

AI가 생성한 코드가 의미와 규칙을 지키고 있는가가 중요해지며, 프롬프트(Prompt), 테스트(Test), 타입(Type)은 각각 서로 다른 입장에서 코드의 의미를 보호합니다.

프롬프트는 어떤 코드를 생성해주길 원하는지 전달합니다

  • 테스트(Test)는 구체적인 입력에 대한 동작을 확인합니다.

타입(Type)은 허용되지 않는 값이나 조작을 프로그램의 후보군에서 제외합니다.

프롬프트(Prompt)로 다음과 같이 지시할 수 있습니다.

주운 돈을 다시 줍지 마세요

테스트(Test)로 다음과 같은 동작을 확인할 수도 있습니다.

주운 돈을 다시 주우려고 하면,
에러가 발생하는 것

Typestate(타입 상태)로서 타입(Type)에 표현하면, 애초에 두 번째 pick을 호출할 수 없는 설계로 만들 수 있습니다.

Money<Picked>에는 pick이 존재하지 않음

마찬가지로, 금액을 Newtype(뉴타입)으로 표현하면, 나이나 개수를 실수로 금액으로서 전달하는 코드도 컴파일(Compile) 시점에 배제할 수 있습니다.

Yen과 Age는 서로 다른 타입

타입(Type)을 세분화하는 목적은, 인간 측에만 존재하던 의미를 컴파일러(Compiler)가 다룰 수 있는 형태로 조금씩 옮기는 것입니다.

데이터의 덩어리
↓
도메인(Domain) 상의 개념
...

이 과정을 통해, 생성된 코드가 중요한 규칙에서 벗어나기 어려워집니다.

설령 AI가 잘못된 코드를 생성하더라도, 타입(Type)으로 표현된 규칙을 위반한다면 컴파일러(Compiler)가 이를 저지합니다.

AI가 코드를 생성한다
↓
타입 검사(Type Check)를 수행한다
...

타입(Type)이 AI가 반드시 올바른 코드를 작성한다는 것을 보장하는 것은 아닙니다.

하지만, 잘못된 코드가 통과할 수 있는 범위를 좁힐 수는 있습니다.

인간 측에 있는 규칙 중 타입(Type)으로 표현할 수 있는 것을 프로그램 측으로 옮기면, 도메인 모델(Domain Model)에 반하는 코드를 컴파일(Compile) 시점에 배제할 수 있습니다.

이것이 중요한 것을 세밀하게 타입(Type)화하는 설계의 목표입니다.

AI 에이전트(AI Agent)에게 작업을 맡길 때도, 중요한 개념, 값의 의미, 상태 전이(State Transition)를 미리 타입(Type)으로 준비해 두면, 에이전트는 컴파일러(Compiler)의 혜택을 받으면서 코드를 생성할 수 있습니다.

인간이 나중에 리뷰(Review)할 때도 다음과 같은 함수 시그니처(Function Signature)가 있다면,

fn pick(self) -> Money<Picked>

구현 내용을 모두 읽기 전에,

줍지 않은 돈을 소비하고,
이미 주운 돈을 반환하는 조작

이라는 의미를 읽어낼 수 있습니다.

타입(Type)은 컴파일러(Compiler)에게 주는 제약인 동시에, 인간과 AI가 공유할 수 있는 실행 가능한 도메인 모델(Domain Model)이기도 합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0