Преобразование списка в структуру с автоматическим преобразованием поля типа

#racket

#racket

Вопрос:

Я читаю файл .csv и с помощью

 (define-struct my-struct (id name))
(apply my-struct '("5" "Tomas"))
(string? (my-struct-id (apply my-struct '("5" "Tomas"))))
  

преобразование его в struct. Однако все поля являются строковыми, есть ли какой-нибудь элегантный способ принудительного string->number преобразования, например, для id поля?

Большое спасибо.

Комментарии:

1. (apply my-struct (map string->number '("5" "Tomas")) ?

2. это нарушает drracket … кроме того, я хочу, чтобы только «5» было преобразовано в number, а не «tomast» в # f

3. Я надеялся на какой-то более автоматический способ, что-то вроде: define-struct my-struct (id #:number name))

Ответ №1:

На мой взгляд, существует два варианта. Первый из них самый простой, используйте пользовательский конструктор:

 ; Option 1: Make a dedicated constructor that
;           handles the conversion.
(struct my-struct (id name) #:transparent)
(define (create-struct id name)
  (my-struct (string->number id) name))
  

Второй вариант — (ab) использовать защиту:

 ; Option 2: Use a guard
(define (converter id name the-struct-name)
  (values (string->number id) name))
(struct my-second-struct (id name) #:guard converter #:transparent)

(apply my-second-struct '("5" "Tomas"))
  

Комментарии:

1. Связано с вариантом 1: когда кто-то хочет предоставить структуру с измененным конструктором, можно сделать это следующим образом: (provide (except-out (struct-out person) person) (rename-out [make-person person]))

Ответ №2:

Чтобы завершить ответ soegaard, если вы предоставляете свою структуру и используете ее в других модулях, вы также можете добавить контракт для предотвращения неправильного использования:

 #lang racket/base
(require racket/contract)
(provide (contract-out
          [struct person ((id number?) (name string?))]))

(struct person (id name))
  
 > (require my-module/person)
> (person 42 "Margaret")
#<person>
> (person "haxxor" 1337)
; person: contract violation
;   expected: number?
;   given: "haxxor"
;   in: the 1st argument of
;       (-> number? string? person?)
  

Смотрите полную документацию здесь: https://docs.racket-lang.org/guide/contracts-struct.html #(part._contracts-define-struct)

Комментарии:

1. Спасибо, я также буду использовать contract, если бы я только мог принять оба ответа.