구조체 유틸리티
구조체 유틸리티 (Structure Utilities)
이 섹션에서는 구조체를 다루는 유틸리티 절차들을 다뤄요. 구조체 타입과 인스턴스를 벡터로 변환하거나, prefab 구조체를 만들고, 프린터를 커스터마이즈하는 데 쓰이는 함수들이 여기 있어요.
출처: Racket Reference
본문
(struct->vector v [opaque-v]) → vector?
v : any/c
opaque-v : any/c = '...
v를 나타내는 벡터를 만들어요. 결과 벡터의 첫 번째 슬롯은 struct:id 형태의 출력 이름을 가진 심볼을 담아요. 나머지 각 슬롯은 현재 코드 검사자(inspector)로 접근 가능하면 v의 필드 값을, 접근 불가능한 필드라면 opaque-v를 담아요. 연속된 접근 불가능 필드에는 벡터에서 하나의 opaque-v 값이 사용돼요. (그 결과, 접근 불가능한 필드가 둘 이상이면 벡터의 크기는 구조체의 크기와 맞지 않아요.)
(struct? v) → any
v : any/c
struct-info가 현재 코드 검사자로 v의 구조체 타입을 하나라도 노출하면 #t, 아니면 #f를 반환해요.
보통 (struct? v)가 참이면 (struct->vector v)가 필드 값을 하나 이상 노출해요. 하지만 v의 유일하게 보이는 타입이 0개의 필드를 기여할 수도 있어요.
(struct-type? v) → boolean?
v : any/c
v가 구조체 타입 기술자 값이면 #t, 아니면 #f를 반환해요.
(struct-constructor-procedure? v) → boolean?
v : any/c
v가 struct나 make-struct-type이 만들어낸 생성자 프로시저이면 #t, 아니면 #f를 반환해요.
(struct-predicate-procedure? v) → boolean?
v : any/c
v가 struct나 make-struct-type이 만들어낸 술어 프로시저이면 #t, 아니면 #f를 반환해요.
(struct-accessor-procedure? v) → boolean?
v : any/c
v가 struct, make-struct-type, 또는 make-struct-field-accessor가 만들어낸 접근자 프로시저이면 #t, 아니면 #f를 반환해요.
(struct-mutator-procedure? v) → boolean?
v : any/c
v가 struct, make-struct-type, 또는 make-struct-field-mutator가 만들어낸 변경자 프로시저이면 #t, 아니면 #f를 반환해요.
(prefab-struct-key v) → (or/c #f symbol? list?)
v : any/c
v가 prefab 구조체 타입의 인스턴스가 아니면 #f를 반환해요. 그렇지 않으면, 그 구조체 타입의 인스턴스를 만들기 위해 make-prefab-struct와 함께 쓸 수 있는 가장 짧은 키를 반환해요.
예제:
> (prefab-struct-key #s(cat "Garfield"))
'cat
> (struct cat (name) #:prefab)
> (struct cute-cat cat (shipping-dest) #:prefab)
> (cute-cat "Nermel" "Abu Dhabi")
'#s((cute-cat cat 1) "Nermel" "Abu Dhabi")
> (prefab-struct-key (cute-cat "Nermel" "Abu Dhabi"))
'(cute-cat cat 1)
(make-prefab-struct key v ...) → struct?
key : prefab-key?
v : any/c
v들을 필드 값으로 사용해 prefab 구조체 타입의 인스턴스를 만들어요. key와 v의 개수가 prefab 구조체 타입을 결정해요.
키는 다음 항목들을 가진 목록을 기반으로 구조체 타입을 식별해요.
- 구조체 타입 이름을 위한 심볼.
- 구조체 타입 안의 비자동(non-automatic) 필드 개수를 나타내는 정확한 음이 아닌 정수. 상위 타입(있으면)의 필드는 세지 않아요.
- 두 항목의 목록. 첫 번째는 상위 타입(있으면)이 아닌 구조체 타입 안의 자동 필드 개수를 위한 정확한 음이 아닌 정수이고, 두 번째 요소는 자동 필드의 값인 임의의 값.
- 구조체 타입 안의 변경 가능한 비자동 필드를 나타내는 정확한 음이 아닌 정수들의 벡터. 0부터 세며 상위 타입(있으면)의 필드는 포함하지 않아요.
- 구조체 타입에 상위 타입이 없으면 그 외 다른 항목은 없다. 그렇지 않으면 목록의 나머지는 상위 타입의 키.
빈 벡터와 0으로 시작하는 자동 필드 목록은 생략할 수 있어요. 또한 (비자동 필드 개수를 나타내는) 첫 번째 정수도 생략할 수 있는데, 제공된 v의 개수로 추론할 수 있기 때문이에요. 마지막으로, 심볼만 담긴 목록 대신 단일 심볼을 쓸 수도 있어요(구조체 타입에 상위 타입도, 자동 필드도, 변경 가능한 필드도 없을 때).
총 필드 개수는 32768을 넘으면 안 돼요. key가 나타내는 필드 개수가 제공된 v의 개수와 일치하지 않으면 exn:fail:contract 예외가 발생해요.
예제:
> (make-prefab-struct 'clown "Binky" "pie")
'#s(clown "Binky" "pie")
> (make-prefab-struct '(clown 2) "Binky" "pie")
'#s(clown "Binky" "pie")
> (make-prefab-struct '(clown 2 (0 #f) #()) "Binky" "pie")
'#s(clown "Binky" "pie")
> (make-prefab-struct '(clown 1 (1 #f) #()) "Binky" "pie")
'#s((clown (1 #f)) "Binky" "pie")
> (make-prefab-struct '(clown 1 (1 #f) #(0)) "Binky" "pie")
'#s((clown (1 #f) #(0)) "Binky" "pie")
(prefab-struct-type-key+field-count type)
→ (or/c #f (cons/c prefab-key? (integer-in 0 32768)))
type : struct-type?
구조체 타입 기술자 type이 prefab 구조체 타입을 나타내면 그 prefab 키와 필드 개수를 담은 쌍을, 아니면 #f를 반환해요.
base 패키지 8.5.0.8 버전에서 추가.
(prefab-key->struct-type key field-count) → struct-type?
key : prefab-key?
field-count : (integer-in 0 32768)
key와 field-count의 조합으로 지정되는 prefab 구조체 타입에 대한 구조체 타입 기술자를 반환해요.
key가 나타내는 필드 개수가 field-count와 일치하지 않으면 exn:fail:contract 예외가 발생해요.
(prefab-key? v) → boolean?
v : any/c
v가 prefab 구조체 타입 키가 될 수 있으면 #t, 아니면 #f를 반환해요.
유효한 키 형태에 대한 설명은 make-prefab-struct를 참고하세요.
5.6.1 추가적인 구조체 유틸리티
(require racket/struct) ; package: base
이 섹션에서 다루는 바인딩은 racket/base나 racket이 아니라 racket/struct 라이브러리가 제공해요.
(make-constructor-style-printer get-constructor get-contents)
→ (-> any/c output-port? (or/c #t #f 0 1) void?)
get-constructor : (-> any/c (or/c symbol? string?))
get-contents : (-> any/c sequence?)
gen:custom-write나 prop:custom-write의 값으로 쓰기 적합한 함수를 만들어내요. 이 함수는 값을 "생성자 스타일(constructor style)"로 출력해요. 값이 표현식으로 출력될 때는 get-constructor가 반환한 생성자를 get-contents가 반환한 내용에 적용한 것으로 보여요. write에 주어지면 생성자와 내용 사이를 콜론으로 구분한 읽을 수 없는 값으로 보여줘요.
예제:
> (struct point (x y)
#:methods gen:custom-write
[(define write-proc
(make-constructor-style-printer
(lambda (obj) 'point)
(lambda (obj) (list (point-x obj) (point-y obj)))))])
> (print (point 1 2))
(point 1 2)
> (write (point 1 2))
#<point: 1 2>
이 함수는 pretty-print과도 협력해요:
> (parameterize ((pretty-print-columns 10))
(pretty-print (point 3000000 4000000)))
(point
3000000
4000000)
> (parameterize ((pretty-print-columns 10))
(pretty-write (point 3000000 4000000)))
#<point:
3000000
4000000>
프린터는 별도의 속성인 prop:custom-print-quotable을 사용해 구조체 인스턴스가 인용 가능한지 결정한다는 점을 기억하세요. 인용 가능하다면 프린터는 목록 안 같은 특정 문맥에서 구조체를 write 모드로 출력할 수 있어요. 예를 들면:
> (print (list (point 1 2) (point 3 4)))
'(#<point: 1 2> #<point: 3 4>)
구조체 인스턴스가 인용 가능한 것으로 간주되지 않게 하려면 #:property prop:custom-print-quotable 'never를 사용하세요. 예를 들면:
> (struct point2 (x y)
#:property prop:custom-print-quotable 'never
#:methods gen:custom-write
[(define write-proc
(make-constructor-style-printer
(lambda (obj) 'point)
(lambda (obj) (list (point2-x obj) (point2-y obj)))))])
> (print (list (point2 1 2) (point2 3 4)))
(list (point 1 2) (point 3 4))
키워드 인자는 unquoted-printing-string으로 흉내낼 수 있어요:
; Private implementation
> (struct kwpoint-impl (x y)
#:methods gen:custom-write
[(define write-proc
(make-constructor-style-printer
(lambda (obj) 'kwpoint)
(lambda (obj)
(list (unquoted-printing-string "#:x")
(kwpoint-impl-x obj)
(unquoted-printing-string "#:y")
(kwpoint-impl-y obj)))))])
; Public ``constructor''
> (define (kwpoint #:x x #:y y)
(kwpoint-impl x y))
; Example use
> (print (kwpoint #:x 1 #:y 2))
(kwpoint #:x 1 #:y 2)
> (write (kwpoint #:x 3 #:y 4))
#<kwpoint: #:x 3 #:y 4>
base 패키지 6.3 버전에서 추가.
(struct->list v [#:on-opaque on-opaque]) → (or/c list? #f)
v : any/c
on-opaque : (or/c 'error 'return-false 'skip) = 'error
구조체 인스턴스 v의 필드를 담은 목록을 반환해요. struct->vector와 달리 구조체 이름 자체는 포함되지 않아요.
v의 어떤 필드든 현재 코드 검사자로 접근할 수 없으면 struct->list의 동작은 on-opaque가 결정해요. on-opaque가 'error(기본값)면 오류가 발생해요. 'return-false면 struct->list는 #f를 반환해요. 'skip이면 접근 불가능한 필드를 목록에서 생략해요.
예제:
> (struct open (u v) #:transparent)
> (struct->list (open 'a 'b))
'(a b)
> (struct->list #s(pre 1 2 3))
'(1 2 3)
> (struct secret open (x y))
> (struct->list (secret 0 1 17 22))
struct->list: expected argument of type <non-opaque struct>;
given: (secret 0 1 ...)
> (struct->list (secret 0 1 17 22) #:on-opaque 'return-false)
#f
> (struct->list (secret 0 1 17 22) #:on-opaque 'skip)
'(0 1)
> (struct->list 'not-a-struct #:on-opaque 'return-false)
#f
> (struct->list 'not-a-struct #:on-opaque 'skip)
'()
base 패키지 6.3 버전에서 추가.
더 알아보기
- 5.2 구조체 타입 만들기:
make-struct-type - prefab 구조체와
make-prefab-struct - 사용자 정의 프린터:
gen:custom-write,prop:custom-write,prop:custom-print-quotable