This is Option's contains() method signature:
pub const fn contains<U>(&self, x: &U) -> bool
where
U: ~const PartialEq<T>
What exactly is that ~const?
This is a new-ish experimental syntax for the const_trait_impl feature.
Remember that the std library can use experimental features even in the stable channel.
Basically, this allows you to implement a trait full all const functions and use it in a const context.
Something like this:
trait MyTrait {
fn foo(&self);
}
struct A;
impl const MyTrait for A {
fn foo(&self) { /* is is a const function! */}
}
struct B;
impl MyTrait for B {
fn foo(&self) { /* is is NOT a const function */}
}
const fn test<X>(x: &X)
where X: ~const MyTrait
{
x.foo();
}
Now a call to test(&A) can be done in a const context while a call to test(&B) cannot. Without the ~const it would never be a const function:
static THE_A: () = test(&A); //ok
static THE_B: () = test(&B); //error: B does not implement MyTrait constly
In the case of the Option implementation, Option::contains() is const if the implementation of T as PartialEq is const.
Related
Reading The Reference here: https://doc.rust-lang.org/reference/items/traits.html
#![allow(unused)]
fn main() {
use std::rc::Rc;
// Examples of non-object safe traits.
trait NotObjectSafe {
const CONST: i32 = 1; // ERROR: cannot have associated const
fn foo() {} // ERROR: associated function without Sized
fn returns(&self) -> Self; // ERROR: Self in return type
fn typed<T>(&self, x: T) {} // ERROR: has generic type parameters
fn nested(self: Rc<Box<Self>>) {} // ERROR: nested receiver not yet supported
}
struct S;
impl NotObjectSafe for S {
fn returns(&self) -> Self { S }
}
let obj: Box<dyn NotObjectSafe> = Box::new(S); // ERROR
}
I want to ask about this:
fn foo() {} // ERROR: associated function without Sized
I am making a proc-macro for get info about an enum.
pub trait EnumReflexion {
/// Returns the identifier of the enum type as an &str
fn enum_name<'a>() -> &'a str;
/// Returns an [`my_proj::my_crate::EnumInfo`] entity that contains
/// runtime reflexive info about `Self`.
fn enum_info<'a>() -> EnumInfo<'a>;
}
Brief piece of the impl on the macro:
let quote = quote! {
impl my_proj::my_crate::EnumReflexion for #ty {
fn enum_name<'a>() -> &'a str {
#ty_str
}
fn enum_info<'a>() -> EnumInfo<'a> {
#enum_info
}
}
};
I can compile my code perfectly fine, and it passes tests like this:
#[test]
fn get_enum_name() {
let variant = EnumMock::A;
assert_eq!("EnumMockd", EnumMock::enum_name());
}
#[derive(EnumInfo)]
enum EnumMock {
A,
B
}
Did that restriction of Sized in associated functions on traits get dropped? Or am I missing something?
I have a function which returns a boxed trait object, and another function that accepts a reference to an object implementing the same trait. I would like to pass a reference to the boxed trait object to the second function, but I am unable to figure out how to do this.
Example simplified code:
trait MyTrait {
fn foo(&self);
}
struct A {}
impl MyTrait for A {
fn foo(&self) {
println!("A");
}
}
struct B {}
impl MyTrait for B{
fn foo(&self) {
println!("B");
}
}
enum MyEnum {
A,
B,
}
fn create_object(my_enum: MyEnum) -> Box<dyn MyTrait> {
let boxed_value: Box<dyn MyTrait> = match my_enum {
MyEnum::A => Box::new(A{}),
MyEnum::B => Box::new(B{}),
};
boxed_value
}
fn do_something<T: MyTrait>(obj: &T) {
obj.foo();
}
fn main() {
use std::borrow::BorrowMut;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow_mut());
}
The error I get:
error[E0282]: type annotations needed
--> src\main.rs:42:5
|
42 | do_something(boxed_value.borrow_mut());
| ^^^^^^^^^^^^ ------------------------ this method call resolves to `&mut Borrowed`
| |
| cannot infer type for type parameter `T` declared on the function `do_something`
Intuitively, I would have hoped that in this case Rust would use dynamic dispatch and wouldn't care about the concrete type T (similarly to what happens in C++ when you pass a reference to a base class), but this seems not to be the case.
How do I pass a reference to the boxed trait object (Box<dyn MyTrait>) to the second function (do_something)? Is this possible in some way? A solution requiring a change to do_something would also be acceptable.
Intuitively, I would have hoped that in this case Rust would use dynamic dispatch and wouldn't care about the concrete type T (similarly to what happens in C++ when you pass a reference to a base class), but this seems not to be the case.
You can make that happen with a cast (or just type ascription, eventually) and by relaxing the default requirement for T to be Sized:
fn do_something<T: MyTrait + ?Sized>(obj: &T) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow() as &dyn MyTrait);
But if you’re not otherwise using T, you can opt into dynamic dispatch on the function side much more simply:
fn do_something(obj: &dyn Borrow) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow());
And if you don’t care that obj is a borrow and want to leave the option of static dispatch open, you can implement MyTrait for &dyn MyTrait:
impl MyTrait for &dyn MyTrait {
fn foo(&self) {
(*self).foo();
}
}
fn do_something<T: MyTrait>(obj: T) {
obj.foo();
}
// or, again, if not otherwise using T:
fn do_something(obj: impl MyTrait) {
obj.foo();
}
use std::borrow::Borrow;
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.borrow());
No matter what, you'll need to add ?Sized to the trait bound in do_something, and then I think you have one of three options:
(Least general) Use as_ref() on the Box when you call do_something.
fn do_something<T: MyTrait + ?Sized>(obj: &T) {
obj.foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value.as_ref());
}
(Most general) Replace the type of obj in do_something with impl AsRef<T>. This will make do_something work with anything convertible to a &T.
fn do_something<T: MyTrait + ?Sized>(obj: impl AsRef<T>) {
obj.as_ref().foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value);
}
(Medium general) Replace the type of obj in do_something with impl Deref<Target=T>. This will make do_something work with any smart pointer holding a T (which is a bit more restrictive than AsRef<T> — a type can implement AsRef<T> for as many values of T as it wants, but only gets to have one Deref implementation).
use std::ops::Deref;
fn do_something<T: MyTrait + ?Sized>(obj: impl Deref<Target=T>) {
obj.deref().foo();
}
fn main() {
let boxed_value = create_object(MyEnum::A);
do_something(boxed_value);
}
Instead of trying to unbox the value
you can instead implement MyTrait on Box<dyn MyTrait>
and forward to the boxed value.
impl MyTrait for Box<dyn MyTrait> {
fn foo(&self) {
self.deref().foo()
}
}
Then you don't even need to call borrow_mut.
fn main() {
use std::borrow::BorrowMut;
let boxed_value = create_object(MyEnum::A);
do_something(&boxed_value);
}
There's a working example in the playground
Here's a minimal example for using an async function in a trait:
use async_trait::async_trait;
macro_rules! default_f {
() => {
async fn f() -> i32 { 0 }
};
}
#[async_trait]
trait Tr {
async fn f() -> i32;
}
struct S;
#[async_trait]
impl Tr for S {
default_f!(); // error: `async` trait functions are not currently supported
//async fn f() -> i32 { 42 } // this compiles
}
Async functions in traits are not supported, yet (rustc 1.53), but the async_trait crate provides a workaround.
The slightly unusual thing, here, is the use of a macro to define a default implementation for the function f.
I don't quite see why I can't use a macro, here. My guess is that the async_trait macro and the the default_f macro don't play well together.
With boilerplate the correct macro looks like this
macro_rules! default_f {
() => {
fn f<'a>() -> Pin<Box<dyn core::future::Future<Output = i32> + Send + 'a>>
where Self: Sync + 'a,
{
async fn f() -> i32 { 42 }
Box::pin(f())
}
};
}
Is there a way to make this work without having to do the boilerplate?
Rust Playground
Let we have the simple trait:
trait Object {
fn new() -> Self
where
Self: Sized;
}
and the struct implemented this trait:
struct Foo { /* internal fields */ }
impl Object for Foo {
fn new() -> Self {
Self { /* some magic */ }
}
}
Now we want to declare static variable in main.rs, for example:
static FOO: Foo = Foo::new();
but we immediately get
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
So, if we want to construct static variables of Foo type, we should declare a function like new, but it should be different function, for example:
impl Foo {
const fn const_new() -> Self { Self { } }
}
static FOO: Foo = Foo::const_new();
But const-twins of trait functions seems very odd. Is there an idiomatic way to write/implement such const counterparts?
UPDATE
I expand answer of #KevinReid for clarity here. Given code works:
pub trait Object {
fn new() -> Self;
}
pub struct Foo {}
impl Foo {
pub const fn new() -> Self { // (1)
Self {}
}
}
impl Object for Foo {
fn new() -> Self { // (2)
println!("A-HA!");
Self::new() // no recursion, calls (1)
}
}
const FOO: Foo = Foo::new(); // calls (1)
fn main() {
let obj: Foo = Object::new(); // calls (2)
let foo = Foo::new(); // calls (1)
}
This code on Rust Playground.
You can rename const_new to just new. When a trait method and an inherent method have the same name, the inherent method is always picked; it is not considered ambiguous.
This way, the same call can be written in both const and generic contexts, and there is no unusual name. (I would also suggest documenting the two functions to mention each other, so people don't assume that because one exists the other doesn't.)
That said, I can't say this idea is idiomatic; I haven't seen it done in a library I've used.
I have a trait that is generic: trait Trait<T> and I want to create another trait that specifies the generics: type Alias = Trait<String>. This would allow impl Alias for T and not have to specify the type parameters. I tried a couple ways of doing this and haven't found any that works.
This is not a duplicate of Type alias for multiple traits or Aliasing trait with associated types because doing trait Alias: Trait<T> requires people to implement Trait<T> anyway. I want to offer a trait that hides the generics.
A clearer code sample:
trait DefaultEvents = Events<UserStruct, ChannelStruct, IrcStruct>;
struct MyHandler;
impl DefaultEvents for MyHandler {
...
}
Here's my best suggestion, it's going to mean a bit more work on your part (with lots of manual trait inheritance), but it should achieve the user convenience that you want.
pub mod user_friendly {
pub trait GivesNum<T> {
fn get_num(&self) -> T;
}
pub trait GivesDouble {
fn get_double(&self) -> f64;
}
impl<S> GivesNum<f64> for S where S: GivesDouble {
fn get_num(&self) -> f64 { self.get_double() }
}
}
// now your library's user needs to do less
use user_friendly::*;
struct MyStruct { num: f64 }
impl GivesDouble for MyStruct {
fn get_double(&self) -> f64 { 2.0 * self.num }
}
fn main() {
let s = MyStruct{ num: 5.0 };
println!("MyStruct.get_num() = {}", s.get_num());
}
Try it on Rust Playground