The docs for Arc<T>
say:
Arc<T>
automatically dereferences toT
(via theDeref
trait), so you can callT
's methods on a value of typeArc<T>
.
But is there any way to allow for matching on Option
-al types?
Here is a simple example:
use std::sync::Arc;
fn main() {
let foo: Arc<Option<String>> = Arc::new(Some("hello".to_string()));
if foo.is_some() {
println!("{}", foo.unwrap());
}
match foo {
Some(hello) => {
println!("{}", hello);
}
None => {}
}
}
The compiler error is:
error[E0308]: mismatched types
--> src/main.rs:11:9
|
11 | Some(hello) => {
| ^^^^^^^^^^^ expected struct `std::sync::Arc`, found enum `std::option::Option`
|
= note: expected type `std::sync::Arc<std::option::Option<std::string::String>>`
found type `std::option::Option<_>`
error[E0308]: mismatched types
--> src/main.rs:14:9
|
14 | None => {}
| ^^^^ expected struct `std::sync::Arc`, found enum `std::option::Option`
|
= note: expected type `std::sync::Arc<std::option::Option<std::string::String>>`
found type `std::option::Option<_>`
No, you cannot match on an Option
inside of an Arc
. To use a type in pattern matching, the implementation of the type must be available to you, but the implementation of Arc
is not public.
In certain cases, you can perform some kind of conversion to be able to match on a reference.
For example, since Arc<T>
implements Deref
, you can use the *
operator to dereference through the Arc<T>
to the underlying T
. Since there's some ergonomic syntax for this kind of matching, you can then take a reference to the value inside the Option
without taking ownership of it:
match *foo {
Some(ref hello) => {
println!("{}", hello);
}
None => {}
}
You can also use Option::as_ref
to convert the &Option<T>
(automatically dereferenced from the Arc<T>
via Deref
) to an Option<&T>
:
match Option::as_ref(&foo) {
Some(hello) => {
println!("{}", hello);
}
None => {}
}
Unfortunately, you can't just call .as_ref()
because the trait method AsRef::as_ref
takes precedence.
In both cases, it's more idiomatic to use if let
if you only care about one of the match arms:
if let Some(ref hello) = *foo {
println!("{}", hello);
}
The first println
passed the early stages of the compiler, but it got flagged by the borrow checker in a later stage. The second println
was an easier fix.
use std::sync::Arc;
fn main() {
let foo: Arc<Option<String>> = Arc::new(Some("hello".to_string()));
if foo.is_some() {
let f1: &Option<String> = foo.as_ref();
let f2: Option<&String> = f1.as_ref();
let f3: &String = f2.unwrap();
println!("{}", f3);
println!("{}", foo.as_ref().as_ref().unwrap())
}
match *foo {
Some(ref hello) => {
println!("{}", hello);
}
None => {}
}
}
The first println
confusingly uses two as_ref()
method calls. The first as_ref
acts on the Arc
, with type signature Fn(&Arc<Option<String>>) -> &Option<String>
. The second one acts on the Option
, with type signature Fn(&Option<String>) -> Option<&String>
playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With