I am currently doing the following:
let line_parts = line.split_whitespace().take(3).collect::<Vec<&str>>();
let ip = line_parts[0];
let bytes = line_parts[1];
let int_number = line_parts[2];
Is it possible to do something like this?
let [ip, bytes, int_number] = line.split_whitespace().take(3).collect();
I'm noticed various references to vector destructuring on some sites but the official docs don't seem to mention it.
It seems what you need is "slice patterns":
fn main() {
let line = "127.0.0.1 1000 what!?";
let v = line.split_whitespace().take(3).collect::<Vec<&str>>();
if let [ip, port, msg] = &v[..] {
println!("{}:{} says '{}'", ip, port, msg);
}
}
Playground link
Note the if let instead of plain let. Slice patterns are refutable, so we need to take this into account (you may want to have an else branch, too).
You can also use this:
use std::convert::TryFrom;
let v = line.split_whitespace().take(3).collect::<Vec<&str>>();
let [ip, bytes, int_number] = <[&str; 3]>::try_from(v).ok().unwrap();
The return type of <[&str; 3]>::try_from(v) will be the Result type which you can use for error handling or allow it to panic as I did, since we already know that the size is 3.
Related
I wanted to reinvent the wheel(reference counting smart pointer) and i am not sure how to properly free the memory leaked with Box::into_raw() , once the references go to zero i don't know how to efficiently free the memory that is being pointed
I originally went with
impl<T> Drop for SafePtr<T>{
fn drop(&mut self) {
//println!("drop, {} refs", self.get_refs());
self.dec_refs();
let ref_count = self.get_refs();
if ref_count == 0usize{
unsafe{
let _ = Box::from_raw(self.ptr);
let _ = Box::from_raw(self.refs);
};
println!("Dropped all pointed values");
};
}
}
but i was wondering if ptr::drop_in_place() would work the same if not better since it won't have to make a Box just to drop it
As you can see from the documentation on into_raw just drop_in_place is not enough, to free the memory you also have to call dealloc:
use std::alloc::{dealloc, Layout};
use std::ptr;
let x = Box::new(String::from("Hello"));
let p = Box::into_raw(x);
unsafe {
ptr::drop_in_place(p);
dealloc(p as *mut u8, Layout::new::<String>());
}
For performance considerations, both methods compile to the exact same instructions, so I'd just use drop(Box::from_raw(ptr)) to save me the hussle remembering the dealloc where applicable.
I'm currently trying to write a function that is generally equivalent to numpy's tile. Currently each time I try to return a (altered or unaltered) clone of the input array, I get a warning about an overflow, and cargo prompts me to increase the recursion limit. however this function isn't recursive, so I'm assuming its happening somewhere in the implementation.
here is the stripped down function, (full version):
pub fn tile<A, D1, D2>(arr: &Array<A, D1>, reps: Vec<usize>) -> Array<A, D2>
where
A: Clone,
D1: Dimension,
D2: Dimension,
{
let num_of_reps = reps.len();
//just clone the array if reps is all ones
let mut res = arr.clone();
let bail_flag = true;
for &x in reps.iter() {
if x != 1 {
bail_flag = false;
}
}
if bail_flag {
let mut res_dim = res.shape().to_owned();
_new_shape(num_of_reps, res.ndim(), &mut res_dim);
res.to_shape(res_dim);
return res;
}
...
//otherwise do extra work
...
return res.reshape(shape_out);
}
this is the actual error I'm getting on returning res:
overflow evaluating the requirement `&ArrayBase<_, _>: Neg`
consider increasing the recursion limit by adding a `#![recursion_limit = "1024"]` attribute to your crate (`mfcc_2`)
required because of the requirements on the impl of `Neg` for `&ArrayBase<_, _>`
511 redundant requirements hidden
required because of the requirements on the impl of `Neg` for `&ArrayBase<OwnedRepr<A>, D1>`rustcE0275
I looked at the implementation of Neg in ndarray, it doesn't seem to be recursive, so I'm a little confused as to what is going on.
p.s. I'm aware there are other errors in this code, as those appeared after I switched from A to f64(the actual type I plan on using the function with), but those are mostly trivial to fix. Still if you have suggestions on any error you see I appreciate them nonetheless.
I am rying to serialize cbor using serde_tokio.
I can make a simple program work, but I need to actually store the tokio_serde::SymmetricallyFramed::new() in a structure to use it more than once.
(It consumes the socket, which is cool).
I can't seem to write a type that will store the value.
use futures::prelude::*;
use tokio::net::TcpStream;
use tokio_serde::formats::*;
use tokio_util::codec::{FramedWrite, LengthDelimitedCodec};
#[tokio::main]
pub async fn main() {
// Bind a server socket
let socket = TcpStream::connect("127.0.0.1:17653").await.unwrap();
// Delimit frames using a length header
let length_delimited = FramedWrite::new(socket, LengthDelimitedCodec::new());
// Serialize frames with JSON
let mut serialized = tokio_serde::SymmetricallyFramed::new(length_delimited, SymmetricalCbor::default());
// Send the value
serialized
.send(vec![1i32,2,3])
.await
.unwrap()
}
produces the right output. (Adopted from the json example in tokio-serde crate, here: https://github.com/carllerche/tokio-serde/blob/master/examples/client.rs
I want to put "serialized" into a structure (and hide how it is created in a fn), but I can't seem to write the right type.
use futures::prelude::*;
use serde_cbor;
use tokio::net::TcpStream;
use tokio_serde::formats::*;
use tokio_util::codec::{FramedWrite, LengthDelimitedCodec};
type CborWriter = tokio_serde::Framed<tokio_util::codec::FramedWrite<tokio::net::TcpStream, tokio_util::codec::LengthDelimitedCodec>, serde_cbor::Value, serde_cbor::Value, tokio_serde::formats::Cbor<serde_cbor::Value, serde_cbor::Value>>;
// something like this has been suggested, but so far no luck.
// fn setup_writer(socket: tokio::net::TcpStream) -> impl Sink<??>+Debug {
fn setup_writer(socket: tokio::net::TcpStream) -> CborWriter {
// Delimit frames using a length header
let length_delimited = FramedWrite::new(socket, LengthDelimitedCodec::new());
// Serialize frames with CBOR
let serialized = tokio_serde::SymmetricallyFramed::new(length_delimited, SymmetricalCbor::default());
return serialized;
}
#[tokio::main]
pub async fn main() {
// Bind a server socket
let socket = TcpStream::connect("127.0.0.1:17653").await.unwrap();
// Serialize frames with CBOR
let mut serialized = setup_writer(socket);
// Send the value
serialized
.send(serde_cbor::Value::Array(vec![serde_cbor::Value::Integer(1i128),
serde_cbor::Value::Integer(2i128),
serde_cbor::Value::Integer(3i128)]))
.await
.unwrap()
}
But, I don't want to put cbor::Value in. I should just be able to put the Serializable objects in. So I am obviously going in the wrong direction here. The JSON example in the tokio-serde crate is happy to put in/out serde_json::Value, but I should have to do that, I think.
A suggestion on Discord was made to change the first example as:
let mut serialized: () = tokio_serde::SymmetricallyFramed::new(length_delimited, SymmetricalCbor::default());
and let the compiler tell me what the type is:
= note: expected unit type `()`
found struct `tokio_serde::Framed<tokio_util::codec::FramedWrite<tokio::net::TcpStream, tokio_util::codec::LengthDelimitedCodec>, _, _, tokio_serde::formats::Cbor<_, _>>`
Well, I can't put _ into the type alias, or write it directly.
I think it should say something like "impl Serialize", but that's not yet a thing.
Obviously, the compiler gets the first example right, so there must be something that will go in there... but what?
I'm trying to write a function that receives a vector of vectors of strings and returns all vectors concatenated together, i.e. it returns a vector of strings.
The best I could do so far has been the following:
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let vals : Vec<&String> = vecs.iter().flat_map(|x| x.into_iter()).collect();
vals.into_iter().map(|v: &String| v.to_owned()).collect()
}
However, I'm not happy with this result, because it seems I should be able to get Vec<String> from the first collect call, but somehow I am not able to figure out how to do it.
I am even more interested to figure out why exactly the return type of collect is Vec<&String>. I tried to deduce this from the API documentation and the source code, but despite my best efforts, I couldn't even understand the signatures of functions.
So let me try and trace the types of each expression:
- vecs.iter(): Iter<T=Vec<String>, Item=Vec<String>>
- vecs.iter().flat_map(): FlatMap<I=Iter<Vec<String>>, U=???, F=FnMut(Vec<String>) -> U, Item=U>
- vecs.iter().flat_map().collect(): (B=??? : FromIterator<U>)
- vals was declared as Vec<&String>, therefore
vals == vecs.iter().flat_map().collect(): (B=Vec<&String> : FromIterator<U>). Therefore U=&String.
I'm assuming above that the type inferencer is able to figure out that U=&String based on the type of vals. But if I give the expression the explicit types in the code, this compiles without error:
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let a: Iter<Vec<String>> = vecs.iter();
let b: FlatMap<Iter<Vec<String>>, Iter<String>, _> = a.flat_map(|x| x.into_iter());
let c = b.collect();
print_type_of(&c);
let vals : Vec<&String> = c;
vals.into_iter().map(|v: &String| v.to_owned()).collect()
}
Clearly, U=Iter<String>... Please help me clear up this mess.
EDIT: thanks to bluss' hint, I was able to achieve one collect as follows:
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
vecs.into_iter().flat_map(|x| x.into_iter()).collect()
}
My understanding is that by using into_iter I transfer ownership of vecs to IntoIter and further down the call chain, which allows me to avoid copying the data inside the lambda call and therefore - magically - the type system gives me Vec<String> where it used to always give me Vec<&String> before. While it is certainly very cool to see how the high-level concept is reflected in the workings of the library, I wish I had any idea how this is achieved.
EDIT 2: After a laborious process of guesswork, looking at API docs and using this method to decipher the types, I got them fully annotated (disregarding the lifetimes):
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let a: Iter<Vec<String>> = vecs.iter();
let f : &Fn(&Vec<String>) -> Iter<String> = &|x: &Vec<String>| x.into_iter();
let b: FlatMap<Iter<Vec<String>>, Iter<String>, &Fn(&Vec<String>) -> Iter<String>> = a.flat_map(f);
let vals : Vec<&String> = b.collect();
vals.into_iter().map(|v: &String| v.to_owned()).collect()
}
I'd think about: why do you use iter() on the outer vec but into_iter() on the inner vecs? Using into_iter() is actually crucial, so that we don't have to copy first the inner vectors, then the strings inside, we just receive ownership of them.
We can actually write this just like a summation: concatenate the vectors two by two. Since we always reuse the allocation & contents of the same accumulation vector, this operation is linear time.
To minimize time spent growing and reallocating the vector, calculate the space needed up front.
fn concat_vecs(vecs: Vec<Vec<String>>) -> Vec<String> {
let size = vecs.iter().fold(0, |a, b| a + b.len());
vecs.into_iter().fold(Vec::with_capacity(size), |mut acc, v| {
acc.extend(v); acc
})
}
If you do want to clone all the contents, there's already a method for that, and you'd just use vecs.concat() /* -> Vec<String> */
The approach with .flat_map is fine, but if you don't want to clone the strings again you have to use .into_iter() on all levels: (x is Vec<String>).
vecs.into_iter().flat_map(|x| x.into_iter()).collect()
If instead you want to clone each string you can use this: (Changed .into_iter() to .iter() since x here is a &Vec<String> and both methods actually result in the same thing!)
vecs.iter().flat_map(|x| x.iter().map(Clone::clone)).collect()
After shamelessly pilfering a code snippet from Tomas Petricek's Blog:
http://tomasp.net/blog/csharp-fsharp-async-intro.aspx
Specifically, this one (and making a few alterations to it):
let downloadPage(url:string) (postData:string) = async {
let request = HttpWebRequest.Create(url)
// Asynchronously get response and dispose it when we're done
use! response = request.AsyncGetResponse()
use stream = response.GetResponseStream()
let temp = new MemoryStream()
let buffer = Array.zeroCreate 4096
// Loop that downloads page into a buffer (could use 'while'
// but recursion is more typical for functional language)
let rec download() = async {
let! count = stream.AsyncRead(buffer, 0, buffer.Length)
do! temp.AsyncWrite(buffer, 0, count)
if count > 0 then return! download() }
// Start the download asynchronously and handle results
do! download()
temp.Seek(0L, SeekOrigin.Begin) |> ignore
let html = (new StreamReader(temp)).ReadToEnd()
return html };;
I tried to do the following with it, and got the error on the last line:
The type was expected to have type Async<'a> but has string -> Asnyc<'a> instead
I googled the error but couldn't find anything that revealed my particular issue.
let postData = "userid=" + userId + "&password=" + password + "&source=" + sourceId + "&version=" + version
let url = postUrlBase + "100/LogIn?" + postData
Async.RunSynchronously (downloadPage(url, postData));;
Also, how would I modify the code so that it downloads a non-ending byte stream (but with occasional pauses between each burst of bytes) asynchronously instead of a string? How would I integrate reading this byte stream as it comes through? I realize this is more than one question, but since they are are all closely related I figured one question would save some time.
Thanks in advance,
Bob
P.S. As I am still new to F# please feel free to make any alterations/suggestions to my code which shows how its done in a more functional style. I'm really trying to get out of my C# mindset, so I appreciate any pointers anyone may wish to share.
Edit: I accidentally pasted in the wrong snippet I was using. I did make an alteration to Tomas' snippet and forgot about it.
When I attempt to run your code downloadPage(url, postData) doesn't work as downloadPage expects two seperate strings. downloadPage url postData is what is expected.
If you changed the let binding to tuple form, or let downloadPage(url:string, postData:string) your call would have worked as well.
To explain why you got the error you got is more complicated. Curried form creates a function that returns a function or string -> string -> Async<string> in your case. The compiler therefore saw you passing a single parameter (tuples are single items after all) and saw that the result would have to be a string -> Async<string> which is not compatible with Async<string>. Another error it could have found (and did in my case) is that string * string is not compatible with string. The exact error being Expected string but found 'a * 'b.
This is what I had:
Async.RunSynchronously (downloadPage(url, postData));;
this is what worked after continued random guessing:
Async.RunSynchronously (downloadPage url postData);;
Although, I'm not sure why this change fixed the problem. Thoughts?