직렬화

직렬화 (Serialization)

serialize는 값을 읽기 가능한(읽을 수 있는) 표현으로 감싸고, deserialize는 그 표현을 다시 원래와 같은 그래프 구조와 가변성을 가진 값으로 복원합니다. 직렬화 가능한 값의 종류와 직렬화 표현의 정확한 형식을 설명합니다.

출처: Racket Reference

본문

(require racket/serialize) ; package: base

이 섹션에 문서화된 바인딩은 racket/serialize 라이브러리가 제공하며, racket/baseracket은 제공하지 않습니다.

procedure

(serializable? v) → boolean?
  v : any/c

v가 직렬화 가능한 것으로 보이면 #t를, 그렇지 않으면 #f를 반환합니다. 복합 값의 내용은 검사하지 않습니다. 직렬화 가능한 값들의 목록은 serialize를 참고하세요.

procedure

(serialize
  v
  [#:relative-directory relative-to
  #:deserialize-relative-directory deserialize-relative-to])

→ any
  v : serializable?
  relative-to : (or/c (and/c path? complete-path?)
      (cons/c (and/c path? complete-path?)
              (and/c path? complete-path?))
      #f)
= #f

  deserialize-relative-to : (or/c (and/c path? complete-path?)
      (cons/c (and/c path? complete-path?)
              (and/c path? complete-path?))
      #f)

   = relative-to

v를 감싸는 값을 반환합니다. 이 값은 읽기 가능한 값들만 포함하므로, writes-exp->fasl로 스트림에 쓸 수 있고, 나중에 readfasl->s-exp로 스트림에서 읽은 뒤, deserialize로 원래와 같은 값으로 변환할 수 있습니다. 직렬화 후 역직렬화(deserialization)하면 원래 값과 같은 그래프 구조와 가변성을 가진 값을 만들어내지만, 직렬화된 값은 평범한 트리입니다(즉 공유가 없음).

다음 종류의 값들이 직렬화 가능합니다:

  • serializable-structserializable-struct/versions로 만들어진 구조체, 또는 더 일반적으로 prop:serializable 속성을 가진 구조체(prop:serializable 참고);
  • prefab 구조체;
  • define-serializable-classdefine-serializable-class*로 정의된 클래스의 인스턴스;
  • 불리언, 숫자, 문자, 내부화(interned) 기호, 읽을 수 없는(unreadable) 기호, 키워드, 문자열, 바이트 문자열, 경로(특정 규약에 대해), regexp 값, #<void>, 빈 리스트;
  • 쌍(pair), 가변 쌍, 벡터, flvector, fxvector, 박스, 해시 테이블, 집합, 트리 리스트(treelist);
  • date, date*, arity-at-least, srcloc 구조체;
  • 모듈 경로 인덱스 값.

복합 값(예: 쌍)의 직렬화는 값의 모든 내용이 직렬화 가능한 경우에만 성공합니다. serialize에 주어진 값이 완전히 직렬화 가능하지 않으면 exn:fail:contract 예외가 발생합니다.

v가 순환(cycle)을 포함하면(즉 서로 모두 도달 가능한 객체들의 모임), v는 그 순환이 가변 값을 포함하는 경우에만 직렬화될 수 있습니다. 여기서 prefab 구조체는 모든 필드가 가변이어야 가변으로 간주됩니다.

relative-to#f가 아니면, relative-to의 경로를 확장하는 직렬화할 경로들은 상대적이고 플랫폼 독립적인 형태로 기록됩니다. relative-to의 가능한 값들과 처리는 current-write-relative-directory와 같습니다.

deserialize-relative-to#f가 아니면, prop:serializable를 통해 추출된 역직렬화기에 대한 경로들은 상대적 형태로 기록됩니다. relative-todeserialize-relative-to는 독립적이지만, deserialize-relative-to는 기본값이 relative-to입니다.

serializedeserialize 함수는 현재 readwrite가 처리할 수 있는 특정 순환 값들(예: '#0=(#0#))을 처리하지 않습니다.

직렬화된 데이터의 형식에 대한 정보는 deserialize를 참고하세요.

base 패키지의 6.5.0.4 버전에서 변경됨: 키워드와 regexp 값을 직렬화 가능하게 추가함. 7.0.0.6 버전에서 변경됨: #:relative-directory#:deserialize-relative-directory 인자 추가.

procedure

(deserialize v) → any
  v : any/c

serialize가 만든 값 v가 주어지면, serialize에 주어진 값과 같은 값(같은 그래프 구조와 가변성을 포함)을 만들어냅니다.

직렬화된 표현 v는 여섯 또는 일곱 요소로 이루어진 리스트입니다:

  • 직렬화 형식의 버전을 나타내는 선택적 리스트 '(1), '(2), '(3) 또는 '(4). 표현의 첫 요소가 리스트가 아니면 버전은 0입니다. 버전 1은 가변 쌍을 지원하고, 버전 2는 읽을 수 없는 기호를 지원하며, 버전 3은 date* 구조체를 지원하고, 버전 4는 역직렬화 디렉터리에 상대적인 경로를 지원합니다.

  • 직렬화된 데이터에 표현된 서로 다른 구조체 타입의 수를 나타내는 음이 아닌 정확한 정수 s-count.

  • 길이 s-count의 리스트 s-types. 각 요소는 구조체 타입을 나타냅니다. 각 구조체 타입은 쌍으로 부호화됩니다. 역직렬화 정보가 최상위에 정의된 구조체면 쌍의 car#f이고, 그렇지 않으면 구조체의 역직렬화 정보를 내보내는 모듈을 나타내는 따옴표 붙은 모듈 경로이거나(bytes->path로 플랫폼 특유의 경로로 변환될 바이트 문자열), current-load-relative-directory 또는 (폴백으로) current-directory에 대해 해석될 모듈의 상대 경로 요소 리스트입니다. 리스트-상대요소 형태는 serialize#:deserialize-relative-directory 인자가 #f가 아닐 때 만들어냅니다. 쌍의 cdr은 (최상위 또는 모듈에서 내보낸) 역직렬화 정보에 대한 바인딩의 이름인데, 기호이거나 읽을 수 없는 기호를 나타내는 문자열입니다. 이 둘은 역직렬화 정보를 얻기 위해 namespace-variable-binding이나 dynamic-require와 함께 사용됩니다. 바인딩 값에 대한 자세한 정보는 make-deserialize-info를 참고하세요. deserialize-module-guard도 참고하세요.

  • 다음 리스트에 포함된 그래프 포인트(graph point)의 수를 나타내는 음이 아닌 정확한 정수 g-count.

  • 길이 g-count의 리스트 graph. 각 요소는 다른 직렬화된 값들의 구성 중에 참조될 직렬화된 값을 나타냅니다. 각 리스트 요소는 박스이거나 박스가 아닙니다:

    • 박스는 순환의 일부인 값을 나타내며, 역직렬화를 위해 각 필드가 #f로 할당되어야 합니다. 박스의 내용은 값의 형태를 나타냅니다:
      • s-types 리스트의 i번째 요소가 나타내는 구조체 타입의 인스턴스에 대한 음이 아닌 정확한 정수 i;
      • 쌍에 대한 'c(쌍은 불변이라 역직렬화 시 실패합니다. 이 경우는 serialize가 만든 출력에는 나타나지 않습니다);
      • 가변 쌍에 대한 'm;
      • 박스에 대한 'b;
      • car'v이고 cdr이 길이 s의 벡터에 대한 음이 아닌 정확한 정수 s인 쌍;
      • 첫 요소가 'h이고 나머지 요소들이 해시 테이블 유형을 결정하는 기호들인 리스트:
        • 'equal(make-hash)
        • 'equal 'weak(make-weak-hash)
        • 'weak(make-weak-hasheq)
        • 기호 없음 — (make-hasheq)
      • 'date*date* 구조체에 대한 것으로, 역직렬화 시 실패합니다(날짜는 불변이라 이 경우는 serialize가 만든 출력에 나타나지 않습니다);
      • 'datedate 구조체에 대한 것으로, 역직렬화 시 실패합니다(날짜는 불변이라 serialize가 만든 출력에 나타나지 않습니다);
      • 'arity-at-leastarity-at-least 구조체에 대한 것으로, 역직렬화 시 실패합니다(arity-at-least는 불변이라 serialize가 만든 출력에 나타나지 않습니다);
      • 'mpi — 모듈 경로 인덱스에 대한 것으로, 역직렬화 시 실패합니다(모듈 경로 인덱스는 불변이라 serialize가 만든 출력에 나타나지 않습니다);
      • 'srclocsrcloc 구조체에 대한 것으로, 역직렬화 시 실패합니다(srcloc는 불변이라 serialize가 만든 출력에 나타나지 않습니다).

    #f로 채워진 값은 직렬화 리스트 v의 다섯 번째 요소가 지정하는 내용으로 갱신됩니다.

    • 박스가 아닌 요소는 즉시 구성될 직렬 값(serial value)이며, 다음 중 하나입니다:
      • 자기 자신을 나타내는 불리언, 숫자, 문자, 내부화 기호 또는 빈 리스트;
      • 불변 문자열을 나타내는 문자열;
      • 불변 바이트 문자열을 나타내는 바이트 문자열;
      • car'?이고 cdr이 음이 아닌 정확한 정수 i인 쌍. graph의 i번째 요소에 대해 구성된 값을 나타내며, igraph 안에서 이 요소의 위치보다 작습니다;
      • car가 숫자 i인 쌍. s-types 리스트의 i번째 요소가 설명하는 구조체 타입의 인스턴스를 나타냅니다. 쌍의 cdr은 구조체 타입의 역직렬화기에 제공될 인자들을 나타내는 직렬 리스트입니다;
      • car'q이고 cdr이 불변 값인 쌍. 따옴표 붙은 값(quoted value)을 나타냅니다;
      • car'f인 쌍. prefab 구조체 타입의 인스턴스를 나타냅니다. 쌍의 cadr는 prefab 구조체 타입 키이고, cddr은 필드 값들을 나타내는 직렬 리스트입니다;
      • car'void인 쌍. #<void>를 나타냅니다;
      • car'su이고 cdr이 문자 문자열인 쌍. 읽을 수 없는 기호를 나타냅니다;
      • car'u이고 cdr이 바이트 문자열 또는 문자 문자열인 쌍. 가변 바이트 또는 문자 문자열을 나타냅니다;
      • car'p이고 cdr이 바이트 문자열인 쌍. 직렬화기의 경로 규약을 사용하는 경로를 나타냅니다('p+를 선호해 폐기됨);
      • car'p+이고 cadr이 바이트 문자열이며 cddrsystem-path-convention-type의 가능한 기호 결과 중 하나인 쌍. 지정된 규약을 사용하는 경로를 나타냅니다;
      • car'p*이고 cdr이 바이트 문자열 리스트인 쌍. 상대 경로를 나타냅니다. 역직렬화가 current-load-relative-directory에 기반해, current-directory로 폴백하며 변환합니다;
      • car'c이고 cdr이 직렬 쌍인 쌍. 불변 쌍을 나타냅니다;
      • car'c!이고 cdr이 직렬 쌍인 쌍. 쌍을 나타내며(과거에는 가변 쌍을 나타냈습니다), serialize가 만든 출력에는 나타나지 않습니다;
      • car'm이고 cdr이 직렬 쌍인 쌍. 가변 쌍을 나타냅니다;
      • car'v이고 cdr이 직렬 리스트인 쌍. 불변 벡터를 나타냅니다;
      • car'v!이고 cdr이 직렬 리스트인 쌍. 가변 벡터를 나타냅니다;
      • car'vl이고 cdr이 직렬 리스트인 쌍. flvector를 나타냅니다;
      • car'vx이고 cdr이 직렬 리스트인 쌍. fxvector를 나타냅니다;
      • car'b이고 cdr이 직렬인 쌍. 불변 박스를 나타냅니다;
      • car'b!이고 cdr이 직렬인 쌍. 가변 박스를 나타냅니다;
      • car'h이고 cadr'! 또는 '-(각각 가변 또는 불변)이며, caddr이 해시 테이블 유형을 결정하는 기호 리스트('equal, 'weak, 둘 다, 또는 둘 다 아님)이고, cdddr이 쌍 리스트(각 쌍의 car는 해시 테이블 키에 대한 직렬, cdr은 대응하는 값에 대한 직렬)인 쌍;
      • car'date*이고 cdr이 직렬 리스트인 쌍. date* 구조체를 나타냅니다;
      • car'date이고 cdr이 직렬 리스트인 쌍. date 구조체를 나타냅니다;
      • car'arity-at-least이고 cdr이 직렬인 쌍. arity-at-least 구조체를 나타냅니다;
      • car'mpi이고 cdr이 쌍인 쌍. 쌍으로 묶인 값들을 결합한 모듈 경로 인덱스를 나타냅니다;
      • car'srcloc이고 cdr이 직렬 리스트인 쌍. srcloc 구조체를 나타냅니다.
  • 쌍들의 리스트. 각 쌍의 car는 음이 아닌 정확한 정수 i이고 cdr은 직렬입니다(이전 불릿에서 정의한). 각 요소는 graph의 i번째 요소(박스로 지정된 것)에 대한 갱신을 나타내며, 직렬은 박스가 지정한 것과 같은 형태의 새 값을 구성하는 방법을 설명합니다. 이 새 값의 내용은 graph에서 박스에 대해 만들어진 값으로 옮겨져야 합니다.

  • deserialize의 결과를 나타내는 마지막 직렬(두 불릿 전에서 정의한).

deserialize의 결과는 deserialize의 인자와 가변 값을 공유하지 않습니다.

serialize에 제공된 값이 단순 트리(즉 공유 없음)라면, 직렬화된 표현의 네 번째와 다섯 번째 요소는 비어 있을 것입니다.

procedure

(serialized=? v1 v2) → boolean?
  v1 : any/c
  v2 : any/c

v1v2가 같은 직렬화 정보를 나타내면 #t를 반환합니다.

더 정확히는, 다음 조건들이 참일 때 (equal? (deserialize v1) (deserialize v2))가 반환할 것과 같은 값을 반환합니다:

  • 역직렬화기가 서로 다른 모듈 경로로 접근되는 모든 구조체 타입이 실제로 서로 다른 타입이고;
  • 모든 구조체 타입이 투명(transparent)하고;
  • 모든 구조체 인스턴스가 v1v2 각각에 기록된 구성 값들만 포함한다면.

parameter

(deserialize-module-guard)
→ (-> module-path? symbol?
    (or/c void? (cons/c module-path? symbol?)))

(deserialize-module-guard guard) → void?
  guard : (-> module-path? symbol?
    (or/c void? (cons/c module-path? symbol?)))

deserializedynamic-require를 통해 모듈을 동적으로 불러오기 전에 호출되는 절차를 값으로 갖는 매개변수입니다. 이 절차에 제공되는 두 인자는 dynamic-require에 전달될 인자와 같습니다. 이 절차는 dynamic-require를 허용하지 않도록 예외를 발생시킬 수 있습니다.

이 절차는 선택적으로 module-pathsymbol을 포함하는 쌍을 반환할 수 있습니다. 반환되면 deserialize는 대신 그것들을 dynamic-require의 인자로 사용합니다.

base 패키지의 6.90.0.30 버전에서 변경됨: 바인딩에 대한 선택적 반환 값 추가.

syntax

(serializable-struct id maybe-super (field ...)
                     struct-option ...)

struct와 같지만, 구조체 타입의 인스턴스들이 serialize로 직렬화 가능합니다. 이 폼은 최상위 또는 모듈의 최상위에서만 허용됩니다(역직렬화 정보를 나중에 찾을 수 있도록).

직렬화는 모든 필드가 가변일 때(또는 순환이 어떤 다른 가변 값을 통해 깨질 수 있을 때)만 만들어진 구조체 타입과 관련된 순환을 지원합니다.

struct가 만드는 바인딩들 외에도, serializable-structdeserialize-info:id-v0를 역직렬화 정보에 바인딩합니다. 게다가 모듈 맥락에서는 module+를 사용해 deserialize-info 하위 모듈에서 이 바인딩을 자동으로 제공합니다.

serializable-struct 폼은 역직렬화가 인스턴스를 구성해야 하므로, id에 접근할 수 없는 장소에서 구조체 인스턴스의 구성을 가능하게 합니다. 게다가 serializable-struct는 필드 변이에 대한 제한된 접근을 제공하지만, deserialize-info:id-v0에 바인딩된 역직렬화 정보를 통해 만들어진 인스턴스에 대해서만 그렇습니다. 자세한 내용은 make-deserialize-info를 참고하세요.

앞 문단은, 예를 들어 직렬화 가능한 struct가 contract-out으로 내보내지면, 역직렬화 중에는 계약이 검사되지 않는다는 것을 의미한다는 점에 주의하세요. 대신 struct-guard/c를 사용하는 것을 고려하세요.

역직렬화 정보의 -v0 접미사는 serializable-struct/versions를 통해 구조체 타입에 대한 향후 버전 관리를 가능하게 합니다.

maybe-super로 상위 타입이 제공되면, 상위 타입 식별자에 바인딩된 컴파일-시간 정보는 상위 타입의 모든 필드 접근자를 포함해야 합니다. 어떤 필드 변이자가 빠져 있으면, 그 구조체 타입은 마샬링(marshaling) 목적으로 불변으로 취급됩니다(그래서 구조체 타입의 인스턴스들만으로 이루어진 순환은 역직렬화기가 처리할 수 없습니다).

예시:

> (serializable-struct point (x y))
> (point-x (deserialize (serialize (point 1 2))))

1

syntax

(define-serializable-struct id-maybe-super (field ...)
                             struct-option ...)

serializable-struct와 같지만, 상위 타입 구문과 기본 생성자 이름이 define-struct의 것과 같습니다.

syntax

(serializable-struct/versions id maybe-super vers (field ...)
                              (other-version-clause ...)
                              struct-option ...)

other-version-clause = (other-vers make-proc-expr
            cycle-make-proc-expr)

serializable-struct와 같지만, 만들어진 역직렬화기 바인딩이 deserialize-info:id-vvers입니다. 게다가 각 other-vers에 대해 deserialize-info:id-vother-vers가 바인딩됩니다. vers와 각 other-vers는 리터럴이고 정확한 음이 아닌 정수여야 합니다.

make-proc-expr은 절차를 만들어내야 하고, 그 절차는 구조체 타입의 해당 버전의 필드 수만큼의 인자를 받아야 하며, id의 인스턴스를 만들어냅니다. 각 cycle-make-proc-expr은 인자 없는 절차를 만들어내야 합니다. 이 절차는 두 값을 반환해야 합니다: id의 인스턴스 x(보통 모든 필드가 #f인)와, 다른 id 인스턴스를 받아 그 필드 값들을 x로 복사하는 절차.

예시:

> (serializable-struct point (x y) #:mutable #:transparent)
> (define ps (serialize (point 1 2)))
> (deserialize ps)

(point 1 2)
> (define x (point 1 10))
> (set-point-x! x x)
> (define xs (serialize x))
> (deserialize xs)

#0=(point #0# 10)
> (serializable-struct/versions point 1 (x y z)
     ([0
       ; Constructor for simple v0 instances:
       (lambda (x y) (point x y 0))
       ; Constructor for v0 instance in a cycle:
       (lambda ()
         (let ([p0 (point #f #f 0)])
           (values
             p0
             (lambda (p)
               (set-point-x! p0 (point-x p))
               (set-point-y! p0 (point-y p))))))])
     #:mutable #:transparent)

> (deserialize (serialize (point 4 5 6)))

(point 4 5 6)
> (deserialize ps)

(point 1 2 0)
> (deserialize xs)

#0=(point #0# 10 0)

syntax

(define-serializable-struct/versions id-maybe-super vers (field ...)
                                     (other-version-clause ...)
                                     struct-option ...)

serializable-struct/versions와 같지만, 상위 타입 구문과 기본 생성자 이름이 define-struct의 것과 같습니다.

procedure

(make-deserialize-info make cycle-make) → any
  make : procedure?
  cycle-make : (-> (values any/c procedure?))

deserialize가 사용할 역직렬화 정보 레코드를 만들어냅니다. 이 정보는 보통 특정 구조체에 묶이는데, 그 구조체가 역직렬화 정보에 바인딩된 최상위 변수 또는 모듈 내보내기 변수를 가리키는 prop:serializable 속성 값을 갖기 때문입니다.

make 절차는 구조체의 직렬화기가 벡터에 넣은 만큼의 인자를 받아야 합니다. 보통 이것은 구조체의 필드 수입니다. 이 절차는 구조체의 인스턴스를 반환해야 합니다.

cycle-make 절차는 인자를 받지 않아야 하며, 두 값을 반환해야 합니다: (더미 필드 값을 가진) 구조체 인스턴스 x와 갱신 절차. 갱신 절차는 make가 만든 다른 구조체 인스턴스를 받아서 그 인스턴스의 필드 값들을 x로 옮깁니다.

value

prop:serializable : struct-type-property?

이 속성은 직렬화 가능한 구조체와 구조체 타입을 식별합니다. 속성 값은 make-serialize-info로 만들어져야 합니다.

procedure

(make-serialize-info to-vector
  deserialize-id
  can-cycle?
  dir) → any

  to-vector : (any/c . -> . vector?)
  deserialize-id : (or identifier?
    symbol?
    (cons/c symbol?
            module-path-index?)
    (-> any/c))

  can-cycle? : any/c
  dir : path-string?

prop:serializable 속성을 통해 구조체 타입과 연관될 값을 만들어냅니다. 이 값은 serialize가 사용합니다.

to-vector 절차는 구조체 인스턴스를 받아 인스턴스 내용에 대한 벡터를 만들어내야 합니다.

deserialize-id 값은 역직렬화 정보에 대한 바인딩(모듈 내보내기 또는 최상위 정의)을 나타냅니다. 다음 중 하나여야 합니다:

  • deserialize-id가 식별자이고 (identifier-binding deserialize-id)가 리스트를 만들어내면, 세 번째 요소가 내보내는 모듈에 사용되고, 그렇지 않으면 최상위가 가정됩니다. 내보내는 모듈을 직접 시도하기 전에, 그 deserialize-info 하위 모듈이 시도됩니다. deserialize-info 하위 모듈을 사용할 수 없거나 내보내기를 찾지 못하면 모듈 자체가 시도됩니다. 어느 경우든 syntax-e를 사용해 내보낸 식별자나 최상위 정의의 이름을 얻습니다.
  • deserialize-id가 기호이면, 그 기호가 이름인 최상위 변수를 나타냅니다.
  • deserialize-id가 쌍이면, car는 내보낸 식별자를 이름 짓는 기호여야 하고, cdr은 내보내는 모듈을 지정하는 모듈 경로 인덱스여야 합니다.
  • deserialize-id가 절차이면, 직렬화 중에 적용되고 그 결과가 deserialize-id로 사용됩니다.

자세한 내용은 make-deserialize-infodeserialize를 참고하세요.

can-cycle? 인자는, 역직렬화가 더미 필드 값을 가진 구조체 인스턴스를 만든 다음 나중에 그 인스턴스를 갱신해야 하도록 인스턴스가 직렬화되지 않아야 한다면 거짓이어야 합니다.

dir 인자는 deserialize-id의 바인딩에 대한 모듈 참조를 해석하는 데 사용되는 디렉터리 경로여야 합니다. 이 디렉터리 경로는 deserialize-id가 최상위에 대해 상대 경로로 불러온 모듈을 나타낼 때 마지막 수단으로 사용됩니다. 보통은 (or (current-load-relative-directory) (current-directory))여야 합니다.

base 패키지의 7.0.0.6 버전에서 변경됨: deserialize-id를 절차로 허용함.

예시:

> (struct pie (type)
    #:mutable
    #:property prop:serializable
    (make-serialize-info
     (λ (this)
       (vector (pie-type this)))
     'pie-beam
     #t
     (or (current-load-relative-directory) (current-directory))))

> (define pie-beam
    (make-deserialize-info
     (λ (type)
       (pie type))
     (λ ()
       (define pie-pattern (pie 'transporter-error))
       (values pie-pattern
               (λ (type)
                 (set-pie-type! pie-pattern type))))))

> (define original-pie
    (pie 'apple))

> original-pie

#<pie>
> (define pie-in-transit
    (serialize original-pie))

> pie-in-transit

'((3) 1 ((#f . pie-beam)) 0 () () (0 apple))
> (define beamed-up-pie
    (deserialize pie-in-transit))

> beamed-up-pie

#<pie>
> (pie-type beamed-up-pie)

'apple
> (equal? beamed-up-pie original-pie)

#f

Serialization Structures

(require racket/serialize-structs) ; package: base

racket/serialize-structs 모듈은 prop:serializable, make-serialize-info, make-deserialize-info만 제공하는데, 이는 직렬화를 지원할 때 의존성을 최소화하는 데 유용합니다.

base 패키지의 8.15.0.3 버전에서 추가되었습니다.

더 알아보기

  • 직렬화 가능한 값들과 관련된 prop:serializable 구조체 타입 속성
  • Racket Guide의 직렬화(Serialization) 문서