Related
I am a beginner in Rust and am trying to create a Parser Combinator library in order to learn the ropes of the language. Very early on in this project I've gotten stuck. I want to have a Parser struct that holds the function used to parse data. Here is my attempt at implementing this.
struct Parser<I, O> {
parse: impl Fn(&Vec<I>) -> Option<(&Vec<I>, O)>
}
Unfortunately, as the compiler informs me, i can not use the "impl Trait" notation in this way. Another way I've tried is by defining a separate type variable for the type of the function itself, as below.
struct Parser<I, O, F>
where
F: impl Fn(&Vec<I>) -> Option<(&Vec<I>, O)>
{
parse: F
}
However, it seems redundant and unnecessary to have to provide the input, output, and function type, as the function type can be derived from the input and output. Also, the compiler gives me an error due to the fact that neither I or O are used.
I also considered Parser may have to be a trait rather than a struct. However I can't really wrap my head around what that would look like, and it seems like you would run into the same issue trying to define a struct that implemented the Parser trait.
Not a lot of context, but you I'll try doing it this way:
struct Parser<I, O> {
parse: Box<dyn Fn(&Vec<I>) -> Option<(&Vec<I>, O)>>,
}
fn main() {
let parser = Parser {
parse: Box::new(|x| {
Some((x, x.iter().sum::<i32>()))
})
};
let v = vec![1, 2, 3, 4];
let result = (parser.parse)(&v).unwrap();
println!("{:?}", result);
}
For some more suggestion I would look here: How do I store a closure in a struct in Rust?
I think all you need is std::marker::PhantomData to silence the error about unused generics. You can also make the code a bit more DRY with some type aliases. (I've replaced &Vec<I> with &[I] as the latter is a strict superset of the former.)
use std::marker::PhantomData;
type Input<'a,I> = &'a [I];
type Output<'a,I,O> = Option<(&'a [I], O)>;
struct Parser<I, O, F>
where
F: Fn(Input<'_,I>) -> Output<'_, I, O>,
{
parse: F,
_phantom: PhantomData<(I, O)>,
}
impl<I, O, F> Parser<I, O, F>
where
F: Fn(Input<'_, I>) -> Output<'_, I, O>,
{
fn new(parse: F) -> Self {
Self {
parse,
_phantom: PhantomData,
}
}
fn parse_it<'a>(&'a self, input: Input<'a, I>) -> Output<'a, I, O> {
(self.parse)(input)
}
}
fn main() {
let parser = Parser::new(|v: &[i32]| Some((v, v.iter().fold(0, |acc, x| acc + x))));
println!("{:?}", parser.parse_it(&[1, 2, 3]));
// ^ Some(([1, 2, 3], 6))
}
I'm trying to test some code which takes a reader. I've got a function:
fn next_byte<R: Read>(reader: &mut R) -> ...
How can I test it on some array of bytes? The docs say that there's a impl<'a> Read for &'a [u8], which would imply this should work:
next_byte(&mut ([0x00u8, 0x00][..]))
But compiler disagrees:
the trait `std::io::Read` is not implemented for the type `[u8]`
Why? I explicitly said &mut.
Using rust 1.2.0
You are trying to invoke next_byte::<[u8]>, but [u8] does not implement Read. [u8] and &'a [u8] are not the same type! [u8] is an unsized array type and &'a [u8] is a slice.
When you use the Read implementation on a slice, it needs to mutate the slice in order for the next read to resume from the end of the previous read. Therefore, you need to pass a mutable borrow to a slice.
Here's a simple working example:
use std::io::Read;
fn next_byte<R: Read>(reader: &mut R) {
let mut b = [0];
reader.read(&mut b);
println!("{} ", b[0]);
}
fn main() {
let mut v = &[1u8, 2, 3] as &[u8];
next_byte(&mut v);
next_byte(&mut v);
next_byte(&mut v);
}
I am very, very new to Rust and trying to implement some simple things to get the feel for the language. Right now, I'm stumbling over the best way to implement a class-like struct that involves casting a string to an int. I'm using a global-namespaced function and it feels wrong to my Ruby-addled brain.
What's the Rustic way of doing this?
use std::io;
struct Person {
name: ~str,
age: int
}
impl Person {
fn new(input_name: ~str) -> Person {
Person {
name: input_name,
age: get_int_from_input(~"Please enter a number for age.")
}
}
fn print_info(&self) {
println(fmt!("%s is %i years old.", self.name, self.age));
}
}
fn get_int_from_input(prompt_message: ~str) -> int {
println(prompt_message);
let my_input = io::stdin().read_line();
let my_val =
match from_str::<int>(my_input) {
Some(number_string) => number_string,
_ => fail!("got to put in a number.")
};
return my_val;
}
fn main() {
let first_person = Person::new(~"Ohai");
first_person.print_info();
}
This compiles and has the desired behaviour, but I am at a loss for what to do here--it's obvious I don't understand the best practices or how to implement them.
Edit: this is 0.8
Here is my version of the code, which I have made more idiomatic:
use std::io;
struct Person {
name: ~str,
age: int
}
impl Person {
fn print_info(&self) {
println!("{} is {} years old.", self.name, self.age);
}
}
fn get_int_from_input(prompt_message: &str) -> int {
println(prompt_message);
let my_input = io::stdin().read_line();
from_str::<int>(my_input).expect("got to put in a number.")
}
fn main() {
let first_person = Person {
name: ~"Ohai",
age: get_int_from_input("Please enter a number for age.")
};
first_person.print_info();
}
fmt!/format!
First, Rust is deprecating the fmt! macro, with printf-based syntax, in favor of format!, which uses syntax similar to Python format strings. The new version, Rust 0.9, will complain about the use of fmt!. Therefore, you should replace fmt!("%s is %i years old.", self.name, self.age) with format!("{} is {} years old.", self.name, self.age). However, we have a convenience macro println!(...) that means exactly the same thing as println(format!(...)), so the most idiomatic way to write your code in Rust would be
println!("{} is {} years old.", self.name, self.age);
Initializing structs
For a simple type like Person, it is idiomatic in Rust to create instances of the type by using the struct literal syntax:
let first_person = Person {
name: ~"Ohai",
age: get_int_from_input("Please enter a number for age.")
};
In cases where you do want a constructor, Person::new is the idiomatic name for a 'default' constructor (by which I mean the most commonly used constructor) for a type Person. However, it would seem strange for the default constructor to require initialization from user input. Usually, I think you would have a person module, for example (with person::Person exported by the module). In this case, I think it would be most idiomatic to use a module-level function fn person::prompt_for_age(name: ~str) -> person::Person. Alternatively, you could use a static method on Person -- Person::prompt_for_age(name: ~str).
&str vs. ~str in function parameters
I've changed the signature of get_int_from_input to take a &str instead of ~str. ~str denotes a string allocated on the exchange heap -- in other words, the heap that malloc/free in C, or new/delete in C++ operate on. Unlike in C/C++, however, Rust enforces the requirement that values on the exchange heap can only be owned by one variable at a time. Therefore, taking a ~str as a function parameter means that the caller of the function can't reuse the ~str argument that it passed in -- it would have to make a copy of the ~str using the .clone method.
On the other hand, &str is a slice into the string, which is just a reference to a range of characters in the string, so it doesn't require a new copy of the string to be allocated when a function with a &str parameter is called.
The reason to use &str rather than ~str for prompt_message in get_int_from_input is that the function doesn't need to hold onto the message past the end of the function. It only uses the prompt message in order to print it (and println takes a &str, not a ~str). Once you change the function to take &str, you can call it like get_int_from_input("Prompt") instead of get_int_from_input(~"Prompt"), which avoids the unnecessary allocation of "Prompt" on the heap (and similarly, you can avoid having to clone s in the code below):
let s: ~str = ~"Prompt";
let i = get_int_from_input(s.clone());
println(s); // Would complain that `s` is no longer valid without cloning it above
// if `get_int_from_input` takes `~str`, but not if it takes `&str`.
Option<T>::expect
The Option<T>::expect method is the idiomatic shortcut for the match statement you have, where you want to either return x if you get Some(x) or fail with a message if you get None.
Returning without return
In Rust, it is idiomatic (following the example of functional languages like Haskell and OCaml) to return a value without explicitly writing a return statement. In fact, the return value of a function is the result of the last expression in the function, unless the expression is followed by a semicolon (in which case it returns (), a.k.a. unit, which is essentially an empty placeholder value -- () is also what is returned by functions without an explicit return type, such as main or print_info).
Conclusion
I'm not a great expert on Rust by any means. If you want help on anything related to Rust, you can try, in addition to Stack Overflow, the #rust IRC channel on irc.mozilla.org or the Rust subreddit.
This isn't really rust-specifc, but try to split functionality into discrete units. Don't mix the low-level tasks of putting strings on the terminal and getting strings from the terminal with the more directly relevant (and largely implementation dependent) tasks of requesting a value, and verify it. When you do that, the design decisions you should make start to arise on their own.
For instance, you could write something like this (I haven't compiled it, and I'm new to rust myself, so they're probably at LEAST one thing wrong with this :) ).
fn validated_input_prompt<T>(prompt: ~str) {
println(prompt);
let res = io::stdin().read_line();
loop {
match res.len() {
s if s == 0 => { continue; }
s if s > 0 {
match T::from_str(res) {
Some(t) -> {
return t
},
None -> {
println("ERROR. Please try again.");
println(prompt);
}
}
}
}
}
}
And then use it as:
validated_input_prompt<int>("Enter a number:")
or:
validated_input_prompt<char>("Enter a Character:")
BUT, to make the latter work, you'd need to implement FromStr for chars, because (sadly) rust doesn't seem to do it by default. Something LIKE this, but again, I'm not really sure of the rust syntax for this.
use std::from_str::*;
impl FromStr for char {
fn from_str(s: &str) -> Option<Self> {
match len(s) {
x if x >= 1 => {
Option<char>.None
},
x if x == 0 => {
None,
},
}
return s[0];
}
}
A variation of telotortium's input reading function that doesn't fail on bad input. The loop { ... } keyword is preferred over writing while true { ... }. In this case using return is fine since the function is returning early.
fn int_from_input(prompt: &str) -> int {
println(prompt);
loop {
match from_str::<int>(io::stdin().read_line()) {
Some(x) => return x,
None => println("Oops, that was invalid input. Try again.")
};
}
}
I have a function which works to make a linked list of integers:
enum List<T> { Cons(T, ~List<T>), End }
fn range(start: int, end: int) -> ~List<int> {
if start >= end { ~End }
else { ~Cons(start, range(start+1, end)) }
}
However, I want to make a range of any numeric type, including uints, doubles and the like. But this, for example, doesn't work:
fn range<T: ord>(start: T, end: T) -> ~List<T> {
if start >= end { ~End }
else { ~Cons(start, range(start+1, end)) }
}
which produces:
> rustc list.rs
list.rs:3:12: 3:15 error: use of undeclared type name `ord`
list.rs:3 fn range<T: ord>(start: T, end: T) -> ~List<T> {
^~~
error: aborting due to previous error
How can I make a generic function in rust which restricts itself to be callable by "numeric" types? Without having to specifically write the interface myself? I had assumed that there were a number of standard-library traits (such as those listed in section 6.2.1.1 of the manual like eq, ord, etc, though now I'm wondering if those are proper "traits" at all) that I could use when declaring generic functions?
The traits are usually uppercase. In this case it is Ord. See if that helps.
In the current master, there is a trait named 'Num' which serves as a general trait for all numeric types. Work has been done recently to unify many of the common math functions to work on this trait rather than u8, f32, etc , specifically.
See https://github.com/mozilla/rust/blob/master/src/libstd/num/num.rs#L26 for the aforementioned Num trait.
Hope this helps!
I'm implementing part of a Scala program that takes input strings of the form "functionName arg1=x1 arg2=x2 ...", parses the xi to the correct types, and then calls a corresponding Scala function functionName(x1,x2,...). The code below is an example implementation with two functions foo and bar, which take different kinds of arguments.
Notice that the types and argument names of foo and bar have to be handwritten into the code in several places: the original function definitions, defining the case classes that the parser returns, and the parsers themselves. The case classes returned by the parser also do basically nothing interesting -- I'm tempted to just call foo and bar from within the parser, but I feel like that would be icky.
My question is: can this implementation be simplified? In practice, I will have many functions with complicated argument types, and I'd prefer to be able to specify those types as few times as possible, and perhaps also not have to define corresponding case classes.
type Word = String
// the original function definitions
def foo(x: Int, w: Word) = println("foo called with " + x + " and " + w)
def bar(y: Int, z: Int) = println("bar called with " + y + " and " + z)
// the return type for the parser
abstract class Functions
case class Foo(x: Int, w: Word) extends Functions
case class Bar(y: Int, z: Int) extends Functions
object FunctionParse extends RegexParsers {
val int = """-?\d+""".r ^^ (_.toInt)
val word = """[a-zA-Z]\w*""".r
val foo = "foo" ~> ("x=" ~> int) ~ ("w=" ~> word) ^^ { case x~w => Foo(x,w) }
val bar = "bar" ~> ("y=" ~> int) ~ ("z=" ~> int) ^^ { case y~z => Bar(y,z) }
val function = foo | bar
def parseString(s: String) = parse(function, s)
}
def main(args: Array[String]) = {
FunctionParse.parseString(args.mkString(" ")) match {
case FunctionParse.Success(result, _) => result match {
case Foo(x, w) => foo(x, w)
case Bar(y, z) => bar(y, z)
}
case _ => println("sux.")
}
}
Edit: I should note that in my case, the specific format above for the input string is not very important -- I'm happy to change it (use xml or whatever) if it results in cleaner, simpler Scala code.
You want reflection, to put it simply. Reflection means finding out, instantiating and calling classes and methods at runtime instead of compile time. For example:
scala> val clazz = Class forName "Foo"
clazz: Class[_] = class Foo
scala> val constructors = clazz.getConstructors
constructors: Array[java.lang.reflect.Constructor[_]] = Array(public Foo(int,java.lang.String))
scala> val constructor = constructors(0)
constructor: java.lang.reflect.Constructor[_] = public Foo(int,java.lang.String)
scala> constructor.getParameter
getParameterAnnotations getParameterTypes
scala> val parameterTypes = constructor.getParameterTypes
parameterTypes: Array[Class[_]] = Array(int, class java.lang.String)
scala> constructor.newInstance(5: Integer, "abc")
res6: Any = Foo(5,abc)
This is all Java reflection. Scala 2.9 still doesn't have a Scala-specific reflection interface, though one is already in development and might well be available on the next version of Scala.
What you're doing looks very reasonable. The only way to 'simplify' it in my mind would be to have less explicit types and/or use reflection to look up the appropriate function...
Update: Daniel's answer is a good example of how to use reflection. In terms of less explicit types, you would have to have the function arguments to be Any...