I'm trying to learn rust via rustlings and I'm encountering this weird error. I understand that it modifies self in place but why does it return a unit () instead of the modified String
impl AppendBar for String {
// TODO: Implement `AppendBar` for type `String`.
fn append_bar(self) -> Self {
self.push_str(" bar")
}
}
I tried to contain it in a variable first but I still get the same error. I was expecting that this would avoid a unit () return type.
impl AppendBar for String {
// TODO: Implement `AppendBar` for type `String`.
fn append_bar(self) -> Self {
let mut contain = self;
contain.push_str(" bar")
}
}
Something like this?
impl AppendBar for String {
fn append_bar(mut self) -> Self {
self.push_str(" bar");
self
}
}
The String::push_str function don't return anything, it mutates the String in place.
So you will you need to mutate the self and return it, in two separated statements.
Related
I'm making my own Serializable trait, in the context of a client / server system.
My idea was that the messages sent by the system is an enum made by the user of this system, so it can be customize as needed.
Too ease implementing the trait on the enum, I would like to use the #[derive(Serializable)] method, as implementing it is always the same thing.
Here is the trait :
pub trait NetworkSerializable {
fn id(&self) -> usize;
fn size(&self) -> usize;
fn serialize(self) -> Vec<u8>;
fn deserialize(id: usize, data: Vec<u8>) -> Self;
}
Now, I've tried to look at the book (this one too) and this example to try to wrap my head around derive macros, but I'm really struggling to understand them and how to implement them. I've read about token streams and abstract trees, and I think I understand the basics.
Let's take the example of the id() method : it should gives a unique id for each variant of the enum, to allow headers of messages to tell which message is incoming.
let's say I have this enum as a message system :
enum NetworkMessages {
ErrorMessage,
SpawnPlayer(usize, bool, Transform), // player id, is_mine, position
MovePlayer(usize, Transform), // player id, new_position
DestroyPlayer(usize) // player_id
}
Then, the id() function should look like this :
fn id(&self) -> usize {
match &self {
&ErrorMessage => 0,
&SpawnPlayer => 1,
&MovePlayer => 2,
&DestroyPlayer => 3,
}
}
Here was my go with writting this using a derive macro :
#[proc_macro_derive(NetworkSerializable)]
pub fn network_serializable_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_network_serializable_macro(&ast)
}
fn impl_network_serializable_macro(ast: &syn::DeriveInput) -> TokenStream {
// get enum name
let ref name = ast.ident;
let ref data = ast.data;
let (id_func, size_func, serialize_func, deserialize_func) = match data {
// Only if data is an enum, we do parsing
Data::Enum(data_enum) => {
// Iterate over enum variants
let mut id_func_internal = TokenStream2::new();
let mut variant_id: usize = 0;
for variant in &data_enum.variants {
// add the branch for the variant
id_func_internal.extend(quote_spanned!{
variant.span() => &variant_id,
});
variant_id += 1;
}
(id_func_internal, (), (), ())
}
_ => {(TokenStream2::new(), (), (), ())},
};
let expanded = quote! {
impl NetworkSerializable for #name {
// variant_checker_functions gets replaced by all the functions
// that were constructed above
fn size(&self) -> usize {
match &self {
#id_func
}
}
/*
#size_func
#serialize_func
#deserialize_func
*/
}
};
expanded.into()
}
So this is generating quite a lot of errors, with the "proc macro NetworkSerializable not expanded: no proc macro dylib present" being first. So I'm guessing there a lot of misunderstaning from my part in here.
I want to move a value into a tuple-type enum variant and obtain a reference to the value after it has been moved. I see how this is possible with an if let statement, but this seems like this should be unnecessary when the particular variant is known statically.
Is there any way to get the reference to the moved value without requiring an if let or match?
This code block is a simple illustration of my question (see below for a more challenging case):
enum Transport {
Car(u32), // horsepower
Horse(String), // name
}
fn do_something(x: &String) {
println!(x);
}
fn main() {
// Can I avoid needing this if, which is clearly redundant?
if let Transport::Horse(ref name) = Transport::Horse("daisy".into()) {
do_something(name);
}
else {
// Can never happen
}
// I tried the following, it gives:
// "error[E0005]: refutable pattern in local binding: `Car(_)` not covered"
let Transport::Horse(ref name) = Transport::Horse("daisy".into());
}
It is easy to find ways to side-step the issue in the above code, since there are no real interface requirements. Consider instead the following example, where I am building a simple API for building trees (where each node can have n children). Nodes have an add_child_node method returning a reference to the node that was added, to allow chaining of calls to quickly build deep trees. (It is debatable whether this is a good API, but that is irrelevant to the question). add_child_node must return a mutable reference to the contents of an enum variant. Is the if let required in this example (without changing the API)?
struct Node {
children: Vec<Child>,
// ...
}
enum Child {
Node(Node),
Leaf
}
impl Node {
fn add_child_node(&mut self, node: Node) -> &mut Node {
self.children.push(Child::Node(node));
// It seems like this if should be unnecessary
if let Some(&mut Child::Node(ref mut x)) = self.children.last() {
return x;
}
// Required to compile, since we must return something
unreachable!();
}
fn add_child_leaf(&mut self) {
// ...
}
}
No. You can use unreachable!() for the else case, and it's usually clear even without message/comment what's going on. The compiler is also very likely to optimize the check away.
If the variants have the same type you can implement AsRef and use the Transport as a &str:
enum Transport {
Car(String),
Horse(String),
}
fn do_something<S: AsRef<str>>(x: &S) {
println!("{}", x.as_ref());
}
impl AsRef<str> for Transport {
fn as_ref(&self) -> &str {
match self {
Transport::Car(s) => s,
Transport::Horse(s) => s,
}
}
}
fn main() {
let transport = Transport::Horse("daisy".into());
do_something(&transport)
}
Playground
Otherwise you need to use a let if binding as you are doing. No need to use an else clause if you don't want to:
if let Transport::Horse(ref name) = Transport::Horse("daisy".into()) {
do_something(name);
}
define From<Transport> for String:
…
impl From<Transport> for String {
fn from(t: Transport) -> String {
match t {
Transport::Car(value) => value.to_string(),
Transport::Horse(name) => name,
}
}
}
fn do_something(x: Transport) {
println!("{}", String::from(x));
}
fn main() {
let horse = Transport::Horse("daisy".to_string());
let car = Transport::Car(150);
do_something(horse);
do_something(car);
}
I'm new to rust.
I'm trying to follow the example for implementing the from_str trait here
https://doc.rust-lang.org/std/str/trait.FromStr.html
But I keep getting this error pointing at 'return Err(Self::Err)'
variant or associated item not found in `black_jack_tools::PlayerDifficulty`
I have an idea of why, Self::Err isn't defined in my enum But I don't get why rust cares in this scenario since I'm returning an Err of my Err object which is inline with the Result<Self,Self::Err> type.
Here's my FromStr is below here's a link to the rust playground with an MRE
impl FromStr for PlayerDifficulty {
type Err = ParseError;
fn from_str(s:&str) -> Result<Self,Self::Err>{
let result = match s {
"Player" => Ok(PlayerDifficulty::Player),
"Dealer" => Ok(PlayerDifficulty::Dealer),
"Normal" => Ok(PlayerDifficulty::Normal),
"Perfect"=> Ok(PlayerDifficulty::Perfect),
"Micky" => Ok(PlayerDifficulty::Micky),
"Elliot" => Ok(PlayerDifficulty::Elliot),
"Cultist"=> Ok(PlayerDifficulty::Cultist),
_ => return Err(Self::Err)
};
}
}
What Am I doing wrong?
Is there a better way to do this?
There are three issues with your code. The first is that you need to use <Self as FromStr>::Err if you want to refer to the Err type in your FromStr implementation:
impl FromStr for PlayerDifficulty {
type Err = ParseError;
fn from_str(s:&str) -> Result<Self,Self::Err>{
let result = match s {
"Player" => Ok(PlayerDifficulty::Player),
/* ... */
_ => return Err(<Self as FromStr>::Err)
};
}
}
Self::Err tries to look for an Err variant in the PlayerDifficulty enum but there is no such variant.
The second issue is that std::string::ParseError is in fact an alias for std::convert::Infallible, which is an error that can never happen and cannot be instantiated. Since your conversion may fail, you need to use an error that can be instantiated or define your own:
struct UnknownDifficultyError;
impl FromStr for PlayerDifficulty {
type Err = UnknownDifficultyError;
fn from_str(s:&str) -> Result<Self,Self::Err>{
let result = match s {
"Player" => Ok(PlayerDifficulty::Player),
/* ... */
_ => return Err(UnknownDifficultyError),
};
}
}
Finally, you need to return the result even when conversion succeeds, by removing the let result = and the semicolon:
struct UnknownDifficultyError;
impl FromStr for PlayerDifficulty {
type Err = UnknownDifficultyError;
fn from_str(s:&str) -> Result<Self,Self::Err>{
match s {
"Player" => Ok(PlayerDifficulty::Player),
/* ... */
_ => return Err(UnknownDifficultyError),
}
}
}
Playground
The function will return it last statement. Remove the last semicolon, and you could also remove the internal return statement, the result of the match statement will be returned.
Is there a better way? It looks like you are parsing a string to a enum, the create enum-utils does that. Instead of implementing the parser with boilerplate code you just derive it.
#[derive(Debug, PartialEq, enum_utils::FromStr)]
enum PlayerDifficulty {
Player,
Dealer,
Cultist,
Normal,
}
fn main() {
let _x:PlayerDifficulty= "Player".parse().unwrap();
}
And in your cargo.toml
[dependencies]
enum-utils = "0.1.2"
You should define a custom error
#[derive(Debug)]
struct PlayerError;
impl std::fmt::Display for PlayerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Could not parse player")
}
}
impl std::error::Error for PlayerError{}
Then change the match always return the Result in the same path
use std::str::FromStr;
impl FromStr for PlayerDifficulty {
type Err = PlayerError;
fn from_str(s:&str) -> Result<Self,Self::Err>{
match s {
"Player" => Ok(PlayerDifficulty::Player),
"Dealer" => Ok(PlayerDifficulty::Dealer),
"Normal" => Ok(PlayerDifficulty::Normal),
"Perfect"=> Ok(PlayerDifficulty::Perfect),
"Micky" => Ok(PlayerDifficulty::Micky),
"Elliot" => Ok(PlayerDifficulty::Elliot),
"Cultist"=> Ok(PlayerDifficulty::Cultist),
_ => Err(PlayerError)
}
}
}
And use it with ? to propagate error.
fn main() -> (Result<(),Box<dyn std::error::Error>>) {
let _x = PlayerDifficulty::from_str("Player")?;
let _x = PlayerDifficulty::from_str("PlayerPlayer")?;
Ok(())
}
I want to call the following method with arguments, either by passing them or from a closure:
fn set_border(&mut self, arg: &str, is_left_border: bool) -> () {
let val = arg.parse::<f64>();
match val {
Ok(float) => { if is_left_border {self.left_border = Some(float)} else {self.right_border = Some(float)}},
Err(_) => {}
}
}
when text is entered to the textbox. I didn't find a way to use lens to access methods, but I'm quite new to rust and decided to ask for advice.
As far as I'm concerned if I can "track" changes of the field and do it that way it will also do.
Thanks in advance.
You can use a Controller to be called when the TextBox receives a call to its update method and then check whether the data has changed:
use druid::{
AppLauncher,
WidgetExt,
Widget,
Env,
UpdateCtx,
WindowDesc,
widget::TextBox,
widget::Controller
};
struct UpdateCallback();
impl Controller<String, TextBox<String>> for UpdateCallback {
fn update(&mut self,
child: &mut TextBox<String>,
ctx: &mut UpdateCtx<'_, '_>,
old_data: &String,
data: &String,
env: &Env
) {
if old_data != data {
// the data has changed, you can call your function here
println!("{}", data);
}
// also inform the child that the data has changed
child.update(ctx, old_data, data, env)
}
}
fn build_root_widget() -> impl Widget<String> {
TextBox::new().controller(UpdateCallback())
}
fn main() {
AppLauncher::with_window(WindowDesc::new(build_root_widget)).launch("Test".to_string()).unwrap();
}
The relevant part here is the Controller impl for UpdateCallback as well as the call to controller() inside the build_root_widget() function.
This is my example code. I am trying to pass a Vec<T> to a function where T: Into<_>!
enum Test {
FN(Box<dyn Fn()>),
STR(String),
}
impl<F> From<F> for Test
where F: Fn() + 'static
{
fn from(f: F) -> Self {
Self::FN(Box::new(f))
}
}
impl From<String> for Test {
fn from(s: String) -> Self {
Self::STR(s)
}
}
fn main() {
into(vec![
|| println!("func 1"),
|| println!("func 2"),
String::from("string 1"),
]);
}
fn into<T>(v: Vec<T>)
where T: Into<Test>
{
for test in v {
let test = test.into();
match test {
Test::FN(func) => func(),
Test::STR(s) => println!("{}", s),
}
}
}
The error is at the second closure:
expected closure, found a different closure
The problem is that Into<_> can't be dyn because it is Sized, so that doesn't work!
I am hoping for an output of:
func 1
func 2
string 1
Any answers or ideas?!
Rust does not generally do type coercion automatically. You've defined your From implementations, but nothing is calling them. You'd need to change your function to be more along the lines of
fn main() {
into(vec![
Test::from(|| println!("func 1")),
Test::from(|| println!("func 2")),
Test::from(String::from("string 1")),
]);
}
Just because you create a Test enum does not mean that Rust will reconcile the type of your otherwise heterogenous vector to be Test. You must manually instantiate each enum variant (and put a Box around your closures):
fn main() {
let x: Vec<Test> = vec![
Test::FN(Box::new(|| println!("func 1"))),
Test::FN(Box::new(|| println!("func 2"))),
Test::STR(String::from("string 1")),
];
into(x);
}
Your idea is to have a Vec of objects all being convertable to test. Yet Vec requires objects of the same type:
each closure has a different type
String is different from closure types
An example with a Vec with elements of the same type could be a Vecof just one of your elements:
into(vec![|| println!("func 1")]);
into(vec![|| println!("func 2")]);
into(vec![String::from("string 1")]);
// each has one element of ONE type, this compiles and runs
or a Vec of multiple elements of the same type:
into(vec![String::from("string 1"), String::from("string 2")]);
// each has multiple element of ONE type (String), this compiles and runs
To get your example to compile you will have to wrap your items in a wrapper type (e.g. an enum) that implements Into<Test>.
Your concrete example already contains such a wrapper type (Test) and thus your example unfortunately gets trivial, because if you put already Tests in your Vec you will not have to call into on them any more (this is shown in the other examples).
Thank you for all the answers,
I found my own solution by creating my own MyInto trait:
trait MyInto {
fn my_into(&self) -> Test;
}
enum Test<'l> {
FN(&'l dyn Fn()),
STR(String),
}
impl<F> MyInto for F
where F: Fn() + 'static
{
fn my_into(&self) -> Test {
Test::FN(self)
}
}
impl MyInto for String {
fn my_into(&self) -> Test {
Test::STR(self.to_owned())
}
}
fn main() {
into(vec![
&|| println!("func 1"),
&|| println!("func 2"),
&String::from("string 1"),
]);
}
fn into(v: Vec<&dyn MyInto>) {
for test in v {
let test = test.my_into();
match test {
Test::FN(func) => func(),
Test::STR(s) => println!("{}", s),
}
}
}
The output is now:
func 1
func 2
string 1
It is now possible to use the dyn in &dyn MyInto, because MyInto is not Sized!