重载结构构造函数? [英] Overloading a struct constructor?
问题描述
我的问题与这里的问题相同,但那里给出的答案没有实际上不起作用.
My question is the same as the one asked here, but the answer given there doesn't actually work.
我有一堆从父结构 A
继承的结构,它有两个字段,我想让它的所有后代都可选.以前我使用 #:auto
,但事实证明这不是我想要的,因为它破坏了像 struct-copy
这样的方法,而且我确实希望能够可选择在结构创建时为这些字段提供值.
I have a bunch of structs inheriting from a parent struct A
, which has two fields that I want to make optional for all its descendants. Previously I was using #:auto
, but that turns out to really not be what I want because it breaks methods like struct-copy
, and also I do want to be able to optionally supply values for those fields on struct creation.
我发现了一些关于结构体可选参数的其他问题,但答案都建议定义一个自定义构造函数并改用它.不幸的是,我已经有很多使用常规构造函数的代码,所以我真正想要的是这个自定义构造函数与结构本身具有相同的名称.我链接的问题的答案是我正在寻找的,但不幸的是它只适用于 REPL,因为允许重复定义.在 REPL 之外,我收到一个错误,例如 module:duplicate definition for identifier in: exn:my-app
,例如(运行链接问题的答案时).
I've found a few other questions about optional arguments for structs, but the answers have all suggested defining a custom constructor and using that instead. Unfortunately I already have a lot of code using the regular constructors, so what I really want is for this custom constructor to have the same name as the struct itself. The answer to the question I linked was what I was looking for, but unfortunately it only works in the REPL because there duplicate definitions are allowed. Outside of the REPL I get an error like module: duplicate definition for identifier in: exn:my-app
, for example (when running the answer to the linked question).
我知道重复定义问题是因为 struct id 也绑定到转换器.我不想阻止这个定义发生;我想要一个名称绑定到该结构的构造函数和转换器,其中构造函数不是默认的.
edit: I know the duplicate definition problem is because the struct id is also bound to a transformer. I don't want to stop that definition from happening; I want a name bound to both a constructor and a transformer for that struct, where the constructor is not the default one.
有没有一种方法可以很好地处理现有代码?
Is there a way to do this that will play nicely with existing code?
推荐答案
进一步研究 soegaard 的新结构关键字提到过,我想我已经提出了一个更简洁的解决方案,更重要的是,更容易抽象为宏(那些模块和需求让我很难过).我想我会分享它以备将来参考.同样,这需要夜间 Racket 构建之一.我使用的是 6.5.0.7.
Looking further into the new struct keywords that soegaard mentioned, I think I've come up with a solution that's a bit cleaner and, more importantly, much easier to abstract into a macro (those modules and requires were giving me a really hard time). I thought I'd share it for future reference. Again, this requires one of the nightly Racket builds. I'm using 6.5.0.7.
(注意:这里使用 case-lambda
而不是定义关键字参数只是我的偏好.)
(Note: the use of case-lambda
over defining keyword arguments here is just my preference.)
#lang racket
(require (for-syntax syntax/transformer))
(struct horse (color)
#:name Horse
#:constructor-name Horse
#:transparent)
(define make-horse
(case-lambda
[() (Horse "black")]
[(color) (Horse color)]))
(define-match-expander horse
; match expander
(λ (pat)
(syntax-case pat ()
[(_ more ...) #'(Horse more ...)]))
; constructor
; edit: changing this to use make-variable-like-transformer,
; as suggested in the comments.
#;(syntax-id-rules ()
[(_ args ...) (make-horse args ...)]
[horse Horse])
(make-variable-like-transformer #'make-horse))
示例用法:
> (define black-beauty (horse))
> black-beauty
(horse "black")
> (define ginger (horse "red"))
> ginger
(horse "red")
> (match black-beauty
[(horse color) color])
"black"
> (match ginger
[(horse color) color])
"red"
> (horse-color black-beauty)
"black"
> (horse-color ginger)
"red"
简而言之:如果您刚刚使用了 struct
,那么实例化、匹配和访问字段似乎就像您期望的那样工作.struct id 也可以用作标识符而没有任何语法问题.我真的不认为那部分有太多实际用途,但我认为它很好.
In short: instantiation, matching, and accessing fields seem to work as you would expect if you'd just used struct
. The struct id can also be used as an identifier without any syntax issues. I don't really think that part has much practical use, but I thought it was nice.
这篇关于重载结构构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!