직렬화
직렬화 (Serialization)
serialize는 값을 읽기 가능한(읽을 수 있는) 표현으로 감싸고, deserialize는 그 표현을 다시 원래와 같은 그래프 구조와 가변성을 가진 값으로 복원합니다. 직렬화 가능한 값의 종류와 직렬화 표현의 정확한 형식을 설명합니다.
출처: Racket Reference
본문
(require racket/serialize) ; package: base
이 섹션에 문서화된 바인딩은 racket/serialize 라이브러리가 제공하며, racket/base나 racket은 제공하지 않습니다.
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를 감싸는 값을 반환합니다. 이 값은 읽기 가능한 값들만 포함하므로, write나 s-exp->fasl로 스트림에 쓸 수 있고, 나중에 read나 fasl->s-exp로 스트림에서 읽은 뒤, deserialize로 원래와 같은 값으로 변환할 수 있습니다. 직렬화 후 역직렬화(deserialization)하면 원래 값과 같은 그래프 구조와 가변성을 가진 값을 만들어내지만, 직렬화된 값은 평범한 트리입니다(즉 공유가 없음).
다음 종류의 값들이 직렬화 가능합니다:
serializable-struct나serializable-struct/versions로 만들어진 구조체, 또는 더 일반적으로prop:serializable속성을 가진 구조체(prop:serializable참고);- prefab 구조체;
define-serializable-class나define-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-to와 deserialize-relative-to는 독립적이지만, deserialize-relative-to는 기본값이 relative-to입니다.
serialize와 deserialize 함수는 현재 read와 write가 처리할 수 있는 특정 순환 값들(예: '#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가 만든 출력에 나타나지 않습니다);'date—date구조체에 대한 것으로, 역직렬화 시 실패합니다(날짜는 불변이라serialize가 만든 출력에 나타나지 않습니다);'arity-at-least—arity-at-least구조체에 대한 것으로, 역직렬화 시 실패합니다(arity-at-least는 불변이라serialize가 만든 출력에 나타나지 않습니다);'mpi— 모듈 경로 인덱스에 대한 것으로, 역직렬화 시 실패합니다(모듈 경로 인덱스는 불변이라serialize가 만든 출력에 나타나지 않습니다);'srcloc—srcloc구조체에 대한 것으로, 역직렬화 시 실패합니다(srcloc는 불변이라serialize가 만든 출력에 나타나지 않습니다).
#f로 채워진 값은 직렬화 리스트v의 다섯 번째 요소가 지정하는 내용으로 갱신됩니다.- 박스가 아닌 요소는 즉시 구성될 직렬 값(serial value)이며, 다음 중 하나입니다:
- 자기 자신을 나타내는 불리언, 숫자, 문자, 내부화 기호 또는 빈 리스트;
- 불변 문자열을 나타내는 문자열;
- 불변 바이트 문자열을 나타내는 바이트 문자열;
car가'?이고cdr이 음이 아닌 정확한 정수i인 쌍.graph의 i번째 요소에 대해 구성된 값을 나타내며,i는graph안에서 이 요소의 위치보다 작습니다;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이 바이트 문자열이며cddr이system-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
v1과 v2가 같은 직렬화 정보를 나타내면 #t를 반환합니다.
더 정확히는, 다음 조건들이 참일 때 (equal? (deserialize v1) (deserialize v2))가 반환할 것과 같은 값을 반환합니다:
- 역직렬화기가 서로 다른 모듈 경로로 접근되는 모든 구조체 타입이 실제로 서로 다른 타입이고;
- 모든 구조체 타입이 투명(transparent)하고;
- 모든 구조체 인스턴스가
v1과v2각각에 기록된 구성 값들만 포함한다면.
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?)))
deserialize가 dynamic-require를 통해 모듈을 동적으로 불러오기 전에 호출되는 절차를 값으로 갖는 매개변수입니다. 이 절차에 제공되는 두 인자는 dynamic-require에 전달될 인자와 같습니다. 이 절차는 dynamic-require를 허용하지 않도록 예외를 발생시킬 수 있습니다.
이 절차는 선택적으로 module-path와 symbol을 포함하는 쌍을 반환할 수 있습니다. 반환되면 deserialize는 대신 그것들을 dynamic-require의 인자로 사용합니다.
base 패키지의 6.90.0.30 버전에서 변경됨: 바인딩에 대한 선택적 반환 값 추가.
syntax
(serializable-struct id maybe-super (field ...)
struct-option ...)
struct와 같지만, 구조체 타입의 인스턴스들이 serialize로 직렬화 가능합니다. 이 폼은 최상위 또는 모듈의 최상위에서만 허용됩니다(역직렬화 정보를 나중에 찾을 수 있도록).
직렬화는 모든 필드가 가변일 때(또는 순환이 어떤 다른 가변 값을 통해 깨질 수 있을 때)만 만들어진 구조체 타입과 관련된 순환을 지원합니다.
struct가 만드는 바인딩들 외에도, serializable-struct는 deserialize-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-info와 deserialize를 참고하세요.
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) 문서