I'm currently trying to learn Rust, and when I was trying to follow the official book tutorial I have encountered an error that was not described in the book.
use std::env;
use std::fs;
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::new(&args);
println!("Searching for {}", config.query);
println!("In file {}", config.filename);
println!("{:?}", args);
let contents = fs::read_to_string(config.filename)
.expect("Something went wrong reading the file");
println!("With text:\n{}", contents);
}
struct Config {
query: String,
filename: String,
}
impl Config {
fn new(args: &[String]) -> Config {
let query = &args[1].clone();
let filename = &args[2].clone();
Config { query, filename }
}
}
but I kept getting the following error from the compiler:
error[E0308]: mismatched types
--> src/main.rs:25:18
|
25 | Config { query, filename }
| ^^^^^
| |
| expected struct `std::string::String`, found `&str`
| help: try using a conversion method: `query: query.to_string()`
error[E0308]: mismatched types
--> src/main.rs:25:25
|
25 | Config { query, filename }
| ^^^^^^^^
| |
| expected struct `std::string::String`, found `&std::string::String`
| help: try using a conversion method: `filename: filename.to_string()`
error: aborting due to 2 previous errors
I have tried doing something like:
let query = &args[1].clone().to_string();
let filename = &args[2].clone().to_owned().to_string();
but it brought the same error. Finally, I have managed to solve this issue by applying the following changes:
struct Config<'a> {
query: &'a str,
filename: &'a str,
}
impl Config <'_> {
fn new(args: &[String]) -> Config {
let query = &*args[1];
let filename = &*args[2];
Config { query, filename }
}
}
My understanding is that new() could not return a struct of owned strings because values query and filename were assigned referenced values and for some reason, neither of the functions to_string(), to_owned() and clone() were not converting a referenced Sting into an owned one.
Does anyone know why I had to use referenced sices with lifetimes instead of strings?
Also, is there a way to use String type just like in the tutorial(https://doc.rust-lang.org/book/ch12-03-improving-error-handling-and-modularity.html)?
the query and file name type is &String, the clone method use &self, You should do like this
impl Config {
fn new(args: &[String]) -> Config {
let query = args[1].clone();
let filename = args[2].clone();
Config { query, filename }
}
}
Related
I'm using axum and this code (found here) to download files:
use axum::{
body::StreamBody,
http::{header, StatusCode},
response::{Headers, IntoResponse},
routing::get,
Router,
};
use std::net::SocketAddr;
use tokio_util::io::ReaderStream;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handler));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler() -> impl IntoResponse {
// `File` implements `AsyncRead`
let file = match tokio::fs::File::open("Cargo.toml").await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
};
// convert the `AsyncRead` into a `Stream`
let stream = ReaderStream::new(file);
// convert the `Stream` into an `axum::body::HttpBody`
let body = StreamBody::new(stream);
let headers = Headers([
(header::CONTENT_TYPE, "text/toml; charset=utf-8"),
]);
Ok((headers, body))
}
Everything works. But I cannot find a way to move the below code in a separate function:
let file = match tokio::fs::File::open("Cargo.toml").await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
};
I would like to use both tokio::fs::File and https://crates.io/crates/rust-s3 methods in this function.
So I need a "common type" which appear to be AsyncRead, I think.
What should be the signature of the function?
I tried with:
use tokio::io::AsyncRead;
pub struct Player {
db: Arc<DB>
}
impl Handler {
pub async fn player_pdf(
&self,
id: &str,
) -> Result<&(dyn AsyncRead)> {
//...use id here...
let file = &tokio::fs::File::open("player.pdf").await?;
Ok(file)
}
}
but I get the error:
error[E0308]: mismatched types
|
55 | Ok(file)
| -- ^^^^
| | |
| | expected reference, found struct `tokio::fs::File`
| | help: consider borrowing here: `&file`
| arguments to this enum variant are incorrect
|
= note: expected reference `&dyn tokio::io::AsyncRead`
found struct `tokio::fs::File`
I tried with: let file = &tokio::fs::File::open("player.pdf").await?; and I got:
error[E0515]: cannot return value referencing temporary value
|
43 | let file = &tokio::fs::File::open(...
| --------------------------- temporary value created here
...
55 | Ok(file)
| ^^^^^^^^ returns a value referencing data owned by the current function
What can I use?
Returning a generic "boxed" value might be the solution here:
impl Handler {
pub async fn player_pdf(
&self,
id: &str,
) -> Result<Box<dyn AsyncRead>> {
//...use id here...
Ok(Box::new(tokio::fs::File::open("player.pdf").await?))
}
}
Where now there's no dangling reference, it's encapsulated and fully owned.
I want to DER encode a nested data structure using the der crate of the RustCrypto project. I have a Vec of SetOfVecs. There should be a blanket implementation of der::Encode for SetOfVec, but the compiler does not recognize it:
// Add this to Cargo.toml:
// ...
// [dependencies]
// der = { version = "0.6", features = ["alloc", "oid"]}
// main.rs:
use der::{DecodeValue, Encode, Header, Reader, Sequence};
use der::asn1::{ObjectIdentifier, SetOfVec};
struct NestedType(Vec<SetOfVec<ObjectIdentifier>>);
impl<'a> DecodeValue<'a> for NestedType {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
Ok(reader.decode()?)
}
}
impl<'a> Sequence<'a> for NestedType {
fn fields<F, T>(&self, field_encoder: F) -> der::Result<T>
where
F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
{
// This works
// (the following 3 lines are just for comparison with the failing case)
let encoder1 = SetOfVec::<ObjectIdentifier>::new();
let encoder2 = SetOfVec::<ObjectIdentifier>::new();
field_encoder(&[&encoder1, &encoder2])?;
// This doesn't work
let mut refs: Vec<&SetOfVec<ObjectIdentifier>> = Vec::new();
for rdn in self.0.iter() {
refs.push(rdn);
}
field_encoder(refs.as_slice())
}
}
fn main() {}
The compiler error:
error[E0308]: mismatched types
--> src\main.rs:33:23
|
33 | field_encoder(refs.as_slice())
| ^^^^^^^^^^^^^^^ expected trait object `dyn Encode`, found struct `SetOfVec`
|
= note: expected reference `&[&dyn Encode]`
found reference `&[&SetOfVec<der::asn1::ObjectIdentifier>]`
As the Encode trait is implemented for SetOfVec, there should be no error. What's the problem here?
Looks like the compiler needs more info. The following code creates a Vec<&dyn Encode> with the references pointing to the SetOfVecs in the original Vec. This should also solve the memory allocation issue, that #Chayim Friedman mentioned (please correct me, if I'm wrong):
impl<'a> Sequence<'a> for NestedType {
fn fields<F, T>(&self, field_encoder: F) -> der::Result<T>
where
F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
{
let mut refs: Vec<&dyn Encode> = Vec::new();
for rdn in self.0.iter() {
refs.push(rdn);
}
field_encoder(refs.as_slice())
}
}
I am trying to create a vector of trait objects but I'm getting a type mismatch. I also tried using .map() instead of a for loop but had the same problem. This is a minimal version of my real code, I realise this example doesn't require the use of trait objects but my real code does since there will be types other than Link in the List, which also implement Speak. How can I create a Vec with the correct type so I can pass it to trait_objects?
use std::fs;
fn main() {
// let links = fs::read_dir("my_dir").unwrap();
// let links: Vec<Box<dyn Speak>> = links
// .map(|file| {
// let myfile = file.unwrap();
// let href = myfile.path().to_str().unwrap();
// Box::new(Link { attr: href })
// })
// .collect();
let links = Vec::new();
for entry in fs::read_dir("my_dir").unwrap() {
let myfile = entry.unwrap();
let href = myfile.path().to_str().unwrap();
links.push(Box::new(Link { attr: href }));
}
let link_objects = ListOfTraitObjects {
trait_objects: links,
};
for link in link_objects.trait_objects.iter() {
println!("{}", link.speak());
}
}
trait Speak {
fn speak(&self) -> String;
}
struct ListOfTraitObjects {
trait_objects: Vec<Box<dyn Speak>>,
}
struct Link<'a> {
attr: &'a str,
}
impl Speak for Link<'_> {
fn speak(&self) -> String {
self.attr.to_string()
}
}
There are several issues with your code. The first is that you're creating a Vec<Box<Link>> instead of a Vec<Box<Speak>>. By default Box::new (foo) creates a box of the same type as foo. If you want a box of some trait implemented by foo, you need to be explicit:
links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
Playground
However this gives two new errors:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:7:20
|
7 | let href = myfile.path().to_str().unwrap();
| ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
8 | links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
| ----------------------------- cast requires that borrow lasts for `'static`
error[E0596]: cannot borrow `links` as mutable, as it is not declared as mutable
--> src/lib.rs:8:9
|
4 | let links = Vec::new();
| ----- help: consider changing this to be mutable: `mut links`
...
8 | links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
The first error is because your Link struct borrows a string from entry, but entry only lives as long as the current loop iteration. Even though the error states that the cast requires a 'static lifetime, you would get a similar error if you were simply trying to build a Vec<Link> without casting (playground). You need to change the definition of your Link struct to contain an owned string:
struct Link {
attr: String,
}
impl Speak for Link {
fn speak(&self) -> String {
self.attr.clone()
}
}
The second error is easier and can be fixed simply by following the compiler suggestion and replacing let links = … with let mut links = ….
Full working example:
use std::fs;
fn main() {
let mut links = Vec::new();
for entry in fs::read_dir("my_dir").unwrap() {
let myfile = entry.unwrap();
let href = myfile.path().to_str().unwrap().to_string();
links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
}
let link_objects = ListOfTraitObjects {
trait_objects: links,
};
for link in link_objects.trait_objects.iter() {
println!("{}", link.speak());
}
}
trait Speak {
fn speak(&self) -> String;
}
struct ListOfTraitObjects {
trait_objects: Vec<Box<dyn Speak>>,
}
struct Link {
attr: String,
}
impl Speak for Link {
fn speak(&self) -> String {
self.attr.clone()
}
}
Playground
The same fixes can be applied to your iterator-based solution:
let links = fs::read_dir("my_dir").unwrap();
let links: Vec<_> = links
.map(|file| {
let myfile = file.unwrap();
let href = myfile.path().to_str().unwrap().to_string();
Box::new(Link { attr: href }) as Box<dyn Speak>
})
.collect();
Playground
I am trying to rewrite an algorithm from javascript to rust. In the following code, I get borrowed value does not live long enough error at line number 17.
[dependencies]
scraper = "0.11.0"
use std::fs;
fn get_html(fname: &str) -> String {
fs::read_to_string(fname).expect("Something went wrong reading the file")
}
pub mod diff_html {
use scraper::{element_ref::ElementRef, Html};
pub struct DiffNode<'a> {
node_ref: ElementRef<'a>,
}
impl<'a> DiffNode<'a> {
fn from_html(html: &str) -> Self {
let doc = Self::get_doc(&html);
let root_element = doc.root_element().to_owned();
let diffn = Self {
node_ref: root_element,
};
diffn
}
fn get_doc(html: &str) -> Html {
Html::parse_document(html).to_owned()
}
}
pub fn diff<'a>(html1: &str, _html2: &str) -> DiffNode<'a> {
let diff1 = DiffNode::from_html(&html1);
diff1
}
}
fn main() {
//read strins
let filename1: &str = "test/test1.html";
let filename2: &str = "test/test2.html";
let html1: &str = &get_html(filename1);
let html2: &str = &get_html(filename2);
let diff1 = diff_html::diff(html1, html2);
//write html
//fs::write("test_outs/testx.html", html1).expect("unable to write file");
//written output file.
}
warning: unused variable: `diff1`
--> src\main.rs:43:9
|
43 | let diff1 = diff_html::diff(html1, html2);
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_diff1`
|
= note: `#[warn(unused_variables)]` on by default
error[E0597]: `doc` does not live long enough
--> src\main.rs:17:32
|
14 | impl<'a> DiffNode<'a> {
| -- lifetime `'a` defined here
...
17 | let root_element = doc.root_element().to_owned();
| ^^^--------------------------
| |
| borrowed value does not live long enough
| assignment requires that `doc` is borrowed for `'a`
...
22 | }
| - `doc` dropped here while still borrowed
I want a detailed explanation/solution if possible.
root_element which is actually an ElementRef has reference to objects inside doc, not the actual owned object. The object doc here is created in from_html function and therefore owned by the function. Because doc is not returned, it is dropped / deleted from memory at the end of from_html function block.
ElementRef needs doc, the thing it is referencing to, to be alive when it is returned from the memory.
pub mod diff_html {
use scraper::{element_ref::ElementRef, Html};
pub struct DiffNode<'a> {
node_ref: ElementRef<'a>,
}
impl<'a> DiffNode<'a> {
fn from_html(html: &'a scraper::html::Html) -> Self {
Self {
node_ref: html.root_element(),
}
}
}
pub fn diff<'a>(html1_string: &str, _html2_string: &str) {
let html1 = Html::parse_document(&html1_string);
let diff1 = DiffNode::from_html(&html1);
// do things here
// at the end of the function, diff1 and html1 is dropped together
// this way the compiler doesn't yell at you
}
}
More or less you need to do something like this with diff function to let the HTML and ElementRef's lifetime to be the same.
This behavior is actually Rust's feature to guard values in memory so that it doesn't leak or reference not referencing the wrong memory address.
Also if you want to feel like operating detachable objects and play with reference (like java, javascript, golang) I suggest reading this https://doc.rust-lang.org/book/ch15-05-interior-mutability.html
I am writing a program to use wirefilter in order to filter data from an infinite stream.
But it seems that I cannot use a compiled ast in a loop because of lifetimes and when I try to compile, this is the output:
error: borrowed data cannot be stored outside of its closure
--> src/main.rs:34:33
|
31 | let filter = ast.compile();
| ------ ...so that variable is valid at time of its declaration
32 |
33 | for my_struct in data.filter(|my_struct| {
| ----------- borrowed data cannot outlive this closure
34 | let execution_context = my_struct.execution_context();
| ^^^^^^^^^ ----------------- cannot infer an appropriate lifetime...
| |
| cannot be stored outside of its closure
error: aborting due to previous error
error: Could not compile `wirefilter_playground`.
To learn more, run the command again with --verbose.
main.rs
use wirefilter::{ExecutionContext, Scheme};
lazy_static::lazy_static! {
static ref SCHEME: Scheme = Scheme! {
port: Int
};
}
#[derive(Debug)]
struct MyStruct {
port: i32,
}
impl MyStruct {
fn scheme() -> &'static Scheme {
&SCHEME
}
fn execution_context(&self) -> ExecutionContext {
let mut ctx = ExecutionContext::new(Self::scheme());
ctx.set_field_value("port", self.port).unwrap();
ctx
}
}
fn main() -> Result<(), failure::Error> {
let data = expensive_data_iterator();
let scheme = MyStruct::scheme();
let ast = scheme.parse("port in {2 5}")?;
let filter = ast.compile();
for my_struct in data.filter(|my_struct| {
let execution_context = my_struct.execution_context();
filter.execute(&execution_context).unwrap()
}).take(10) {
println!("{:?}", my_struct);
}
Ok(())
}
fn expensive_data_iterator() -> impl Iterator<Item=MyStruct> {
(0..).map(|port| MyStruct { port })
}
Cargo.toml
[package]
name = "wirefilter_playground"
version = "0.1.0"
edition = "2018"
[dependencies]
wirefilter-engine = "0.6.1"
failure = "0.1.5"
lazy_static = "1.3.0"
is it possible to make it work? I would like to yield only the filtered data for the final user otherwise the amount of data would be huge in memory.
Thank you in advance!
It looks like the problem is with the lifetime elision in return structs. In particular this code:
fn execution_context(&self) -> ExecutionContext {
//...
}
is equivalent to this one:
fn execution_context<'s>(&'s self) -> ExecutionContext<'s> {
//...
}
Which becomes obvious once you realize that ExecutionContext has an associated lifetime.
The lifetime of ExecutionContext does not have to match that of the MyStruct so you probably want to write:
fn execution_context<'e>(&self) -> ExecutionContext<'e> {
//...
}
or maybe:
fn execution_context<'s, 'e>(&'s self) -> ExecutionContext<'e>
where 'e: 's {
//...
}
depending on whether your context will eventually refer to any content of MyStruct.