-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend &pattern
to general Deref
implementation.
#2099
Comments
Use case or motivating example? Aside from |
@ExpHP just today, I had the case where I had a RAII type derefing to an enum, which I wanted to match against. The code I ended up with was a clusterfuck, because I needed to add another ident for matching against the enum, which is really annoying. If I could just however use |
Is this the same as This would make pattern matching be able to run arbitrary code, which wasn’t the case before. (For example, |
I'm not certain I see the difference from what's possible today. (Playground) struct BigRedButton;
impl ::std::ops::Deref for BigRedButton {
type Target = str;
fn deref(&self) -> &Self::Target {
panic!("launching nukes");
}
}
fn main() {
// Nothing to see here, just a pattern match.
let _:&str = &BigRedButton; // thread 'main' panicked at 'launching nukes'
} |
That’s deref coercion happening on the right-hand-side of the assignment, not pattern matching. But yeah, maybe deref patterns are no big deal. |
Still, because side effects are be involved we’d need to define the order of pattern "evaluation". |
Apologies for the noise; after much faffing about I finally see what the difference is. My mental model of when deref coercions are applied was a bit "off." Apparently they apply to every expression, recursively (AST-wise), but only on the outermost type. fn main() {
let red = BigRedButton;
let borrow: &BigRedButton = &red;
let _:&str = borrow; // compiles
let _:Option<&str> = Some(borrow); // compiles
let _:(&str, &str) = (borrow, borrow); // compiles
let tup: (&BigRedButton,) = (borrow,);
let _: (&str,) = (tup.0,); // compiles
let _: (&str,) = tup; // AHAH! Finally, a type error.
} One could say that the examples that compile are exactly those examples where it is possible to insert "as &str" somewhere on the RHS to make the coercions explicit. |
Pattern matching on recursive enums. Currently, this is impossible without |
You could add a unsafe However, I still feel that that restriction is unessicarry, since we already allow arbitrary code to run in the general case. Personally, I'm often anoyed by the lack of a general solution and the fact that |
It looks like this issue was initially suggested by @nikomatsakis in #2005 (comment) . Some more discussion occurred around this comment (it's a little hard to follow because the thread is intermingled with discussion of a Is there any momentum here? What needs to happen next, a formal RFC written up? |
|
Quick summary of where we are at:
Currently, this works with plain references:
And with
The idea would be to extend the current behaviour of This feature has been mentioned in the discussion around The main objections seem to be:
|
I think that when I made the comment, I was thinking of matching on something like
but you example works just as well. One note about deprecating |
Matching a deep String is another use-case: enum X {
A(String),
// ...
}
fn main() {
match X::A("test".to_string()) {
X::A(&"test") => (),
X::A(_) => ()
}
} |
This comment was marked as spam.
This comment was marked as spam.
@AlbertMarashi and everybody interested! I implemented deref patterns (including strings) in proc macro crate: https://crates.io/crates/match_deref |
For example, suppose
X
derefs, then&pat
takesX
and dereferences it. If the dereferenced value matches patternpat
, it matches.In other words, it extends
&pattern
from only allowing dereferencing of&T
to allowing dereferencing of arbitraryT: Deref
.Alternative is of course to introduce a seperate syntax for it.
The text was updated successfully, but these errors were encountered: