In this example I'm trying to pass a BufWriter to some functions but don't understand generic type syntax enough to figure out whats missing.
Instead of passing the file, I want to pass the buffered writer and could not find any examples of this which would get me out of the weeds.
use std::fs::OpenOptions;
use std::io::BufWriter;
fn main() {
println!("Opening dummy read file");
let write = OpenOptions::new()
.write(true)
.create(true)
.open("DummyWriteFile");
let mut writer = BufWriter::new(write.unwrap());
// do some writes with FunctionA
write_something(&mut writer);
// write something else here with bufwriter
}
fn write_something(outBuf: BufWriter<W>) {}
The error I get is the following:
Compiling playground v0.0.1 (/playground)
error[E0412]: cannot find type `W` in this scope
--> src/main.rs:13:40
|
13 | fn write_something( outBuf: BufWriter <W> ){
| - ^ not found in this scope
| |
| help: you might be missing a type parameter: `<W>`
For more information about this error, try `rustc --explain E0412`.
error: could not compile `playground` due to previous error
You have a couple options.
To make that version of your code work, you need to add W as a generic parameter on the function with a Write bound. And you need to change it to take a mutable reference:
use std::io::Write;
fn write_something<W: Write>(out_buf: &mut BufWriter<W>) {
}
But what you probably want is to use the Write trait bound (since BufWriter impls it) instead of specifying BufWriter directly:
fn write_something(mut out_buf: impl Write) {
// OR: fn write_something<W: Write>(mut out_buf: W) {
}
Related
i have the following code snippet which implements some kind of Emitter Struct:
type Callback<'a> = Option<&'a mut dyn FnMut()>;
struct Emitter<'a> {
cb: Callback<'a>
}
impl<'a> Emitter<'a> {
fn emit(&mut self) {
if self.cb.is_some() {
let f = self.cb.unwrap();
f()
}
}
}
fn main() {
let mut cb = || println!("test");
let mut e = Emitter {
cb : Some(&mut cb)
};
e.emit();
}
The emit() function tries to run the saved callback clojure. But i cannot wrap my head around how to run the callback, since the code produces the following error:
--> src/main.rs:11:15
|
11 | let f = self.cb.unwrap();
| ^^^^^^^
| |
| move occurs because `self.cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `self.cb.as_ref()`
Appreciate some help :)
Here is the snippet on replit: https://replit.com/#lutzer/RustEmitterTest
What's going on here is that your line
let f = self.cb.unwrap();
would want to move the closure out of the Option enum. This operation consumes that enum, which isn't allowed for things that belong to a struct.
Here is a simpler example to show what I mean:
fn main() {
let an_option = Some(String::from("Woot!");
let the_value = an_option.unwrap();
println!("The value is {}", the_value);
println!("The option is {:?}", an_option); // error here! Can't use an_option any more!!!
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4a4a3660b68ebada99113db5165b6e76
So if you take ownership of something stored inside the Some part of an Option, via unwrap, then the whole Option gets moved out. You can see that in the signature of unwrap:
pub const fn unwrap(self) -> T
Note how it says self, and not &self or &mut self. That means, after calling unwrap, that the enum gets consumed and cannot be used any more, unless the value inside the Some part can simply be copied (If you replace the String in my example with, say, an integer, it will compile without issue).
The comment by Omer Erden then explains a way around that: Ask the Option to give you a mutable reference instead via as_mut.
Or skip all that directly and use the map method of option, which you can use to do something if the option is Some and just not do anything if it's None.
I'm trying to write to standard output using the writeln!() instead of the println!() macro, so I can handle I/O errors (e.g. when I pipe long-running output to head) gracefully. I found the following snippet at https://rust-cli.github.io/book/tutorial/output.html#a-note-on-printing-performance, wrapped up here in an error handling function:
use std::io;
fn main() {
if let Err(error) = run() {
eprintln!("{}", error);
}
}
fn run() -> Result<(), io::Error> {
let stdout = io::stdout(); // get the global stdout entity
let mut handle = io::BufWriter::new(stdout); // wrap that handle in a buffer
writeln!(handle, "foo: {}", 42)?; // add ? if you care about errors here
return Ok(());
}
It works on the website "run this code" button, but when I try to build it for myself, I get a compiler error:
error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<std::io::Stdout>` in the current scope
--> src/main.rs:12:5
|
12 | writeln!(handle, "foo: {}", 42)?; // add ? if you care about errors here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<std::io::Stdout>`
|
::: /home/hwalters/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/io/mod.rs:1516:8
|
1516 | fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
| --------- the method is available for `std::boxed::Box<std::io::BufWriter<std::io::Stdout>>` here
|
= help: items from traits can only be used if the trait is in scope
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
1 | use std::io::Write;
|
Going on the "the method is available for..." hint, I tried wrapping the BufWriter in a Box, but this did not make any difference.
I'm using Rust 2018. Is there something I'm missing?
You need to import the std::io::Write trait as the error suggests:
use std::io::Write;
In Rust traits must be imported to be able to use the methods they implement.
It works on the website "run this code" button, but when I try to build it for myself, I get a compiler error:
If you're referring to the "A note on printing performance", which you link to, then it does include the import in the form of use std::io::{self, Write};.
The writeln! macro requires that its first argument has a write_fmt method. By default, io::BufWriter<T> doesn't implement this method, it's only implemented for io::BufWriter<T: io::Write> so to get access to the implementation you have to import the io::Write trait into your code. Fixed example:
use std::io;
use std::io::Write; // need to import this trait
fn main() {
if let Err(error) = run() {
eprintln!("{}", error);
}
}
fn run() -> Result<(), io::Error> {
let stdout = io::stdout();
let mut handle = io::BufWriter::new(stdout);
writeln!(handle, "foo: {}", 42)?;
Ok(())
}
playground
I have a working function foo, which compiles without error:
use chrono;
fn foo() {
let now = chrono::offset::Local::now();
let mut buf = String::new();
buf.push_str(&now.format("%Y/%m/%d").to_string());
}
When I try to extract the now variable to a parameter:
fn foo<T: chrono::TimeZone>(now: chrono::DateTime<T>) {
let mut buf = String::new();
buf.push_str(&now.format("%Y/%m/%d").to_string());
}
I run into this error when compiling:
error[E0599]: no method named `format` found for struct `chrono::DateTime<T>` in the current scope
--> src/lib.rs:108:35
|
108 | buf.push_str(&now.format("%Y/%m/%d").to_string());
| ^^^^^^ method not found in `chrono::DateTime<T>`
|
= note: the method `format` exists but the following trait bounds were not satisfied:
`<T as chrono::TimeZone>::Offset: std::fmt::Display`
The note says that format exists (it does, as in the first code snippet), but trait bounds aren't satisfied. How do I specify the missing trait bound to make this compile?
I'm guessing it should be possible somehow, considering that the first snippet compiles and I'm only extracting the same type as a parameter.
Related chrono docs: https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html
I took a look at the impl block for DateTime. It had code of the form below. I updated the function's signature to match, and it now compiles successfully.
fn foo<T: chrono::TimeZone>(now: chrono::DateTime<T>)
where
T::Offset: std::fmt::Display, {
...
}
I have a RwLock protected global WORLD, and I want to write a function that read locks it and returns an iterator (of type Neighbors) that iterates over edges in a petgraph::stable_graph::StableGraph that is stored inside the global. I'm using OwningRef to deal with keeping the read lock guard alive after the function exits, which has worked for me in the past when just returning a field of World directly. I've included a compilable example and the error I'm getting below -- it seems there is some sort of type problem but I haven't been able to figure it out. I think it might have to do with OwningRef wanting to deal with a reference rather than an object containing a reference (Neighbors) but I'm not sure how to work around that.
Cargo.toml:
[package]
name = "problem_demo"
version = "0.1.0"
authors = ["Joseph Garvin <joseph.h.garvin#gmail.com>"]
edition = "2018"
[dependencies]
owning_ref="0.4.1"
once_cell="1.4.0"
petgraph={version="0.5.1", features=["serde-1"]}
main.rs:
use std::{sync::RwLock};
use once_cell::sync::OnceCell;
use owning_ref::RwLockReadGuardRef;
use petgraph::stable_graph::{StableGraph, Neighbors};
struct Bar {
data: i32
}
struct World {
graph: StableGraph<(), Bar, petgraph::Directed, u32>
}
pub static WORLD: OnceCell<RwLock<World>> = OnceCell::new();
fn neighbors(id: u32) -> Result<RwLockReadGuardRef<'static, World, Neighbors<'static, Bar, u32>>, Box<dyn std::error::Error>> {
RwLockReadGuardRef::new(WORLD.get().unwrap().read().unwrap())
.try_map(
|world: &World| -> std::result::Result<Neighbors<'static, Bar, u32>, Box<dyn std::error::Error>>
{
let neighbors = world.graph.neighbors_directed(
petgraph::graph::NodeIndex::new(id as usize),
petgraph::Direction::Outgoing
);
Ok(neighbors)
}
)
}
Errors:
error[E0271]: type mismatch resolving `for<'r> <[closure#src/main.rs:21:13: 29:14 id:_] as std::ops::FnOnce<(&'r World,)>>::Output == std::result::Result<&'r _, _>`
--> src/main.rs:20:10
|
20 | .try_map(
| ^^^^^^^ expected struct `petgraph::stable_graph::Neighbors`, found reference
|
= note: expected enum `std::result::Result<petgraph::stable_graph::Neighbors<'static, Bar>, std::boxed::Box<dyn std::error::Error>>`
found enum `std::result::Result<&_, _>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
Why doesn't this code compile:
fn use_cursor(cursor: &mut io::Cursor<&mut Vec<u8>>) {
// do some work
}
fn take_reference(data: &mut Vec<u8>) {
{
let mut buf = io::Cursor::new(data);
use_cursor(&mut buf);
}
data.len();
}
fn produce_data() {
let mut data = Vec::new();
take_reference(&mut data);
data.len();
}
The error in this case is:
error[E0382]: use of moved value: `*data`
--> src/main.rs:14:5
|
9 | let mut buf = io::Cursor::new(data);
| ---- value moved here
...
14 | data.len();
| ^^^^ value used here after move
|
= note: move occurs because `data` has type `&mut std::vec::Vec<u8>`, which does not implement the `Copy` trait
The signature of io::Cursor::new is such that it takes ownership of its argument. In this case, the argument is a mutable reference to a Vec.
pub fn new(inner: T) -> Cursor<T>
It sort of makes sense to me; because Cursor::new takes ownership of its argument (and not a reference) we can't use that value later on. At the same time it doesn't make sense: we essentially only pass a mutable reference and the cursor goes out of scope afterwards anyway.
In the produce_data function we also pass a mutable reference to take_reference, and it doesn't produce a error when trying to use data again, unlike inside take_reference.
I found it possible to 'reclaim' the reference by using Cursor.into_inner(), but it feels a bit weird to do it manually, since in normal use-cases the borrow-checker is perfectly capable of doing it itself.
Is there a nicer solution to this problem than using .into_inner()? Maybe there's something else I don't understand about the borrow-checker?
Normally, when you pass a mutable reference to a function, the compiler implicitly performs a reborrow. This produces a new borrow with a shorter lifetime.
When the parameter is generic (and is not of the form &mut T), the compiler doesn't do this reborrowing automatically1. However, you can do it manually by dereferencing your existing mutable reference and then referencing it again:
fn take_reference(data: &mut Vec<u8>) {
{
let mut buf = io::Cursor::new(&mut *data);
use_cursor(&mut buf);
}
data.len();
}
1 — This is because the current compiler architecture only allows a chance to do a coercion if both the source and target types are known at the coercion site.