This page selects some example programs from "Rust by Example" and shows their intended Husht equivalents. (Of course, the details of the syntax on the Husht side may end up varying in some cases for practical reasons from these initial proposals. The examples will be updated when and if they change, and will be used as cases in the eventual Husht test suite.) Comments included in the Husht versions to add detail/explanation are marked with //!
.
Hello World
Rust |
Husht |
// Many comments from the Rust by Example version
// have been removed
fn main() {
// Print text to the console.
println!("Hello World!");
}
|
// Many comments from the Rust by Example version
// have been removed
fn main
// Print text to the console.
println! "Hello World!"
|
Formatted print
(Skipping for now because we likely want "f-strings" in Husht, which require some thought/design.)
Primitives
Rust |
Husht |
fn main() {
let logical: bool = true;
let a_float: f64 = 1.0; // Regular annotation
let an_integer = 5i32; // Suffix annotation
let default_float = 3.0; // `f64`
let default_integer = 7; // `i32`
// Can infer from another line; here i64:
let mut inferred_type = 12;
inferred_type = 4294967296i64;
let mut mutable = 12; // Mutable `i32`
mutable = 21;
// Error! The type of a variable can't be changed.
mutable = true;
// Variables can be overwritten with shadowing.
let mutable = true;
}
|
fn main
let logical: bool = true
let a_float: f64 = 1.0 // Regular annotation
let an_integer = 5i32 // Suffix annotation
let default_float = 3.0 // `f64`
let default_integer = 7 // `i32`
// Can infer from another line; here i64:
let mut inferred_type = 12
inferred_type = 4294967296i64
let mut mutable = 12 // Mutable `i32`
mutable = 21
// Error! The type of a variable can't be changed.
mutable = true
// Variables can be overwritten with shadowing.
let mutable = true
|
Literals and operators
Not really anything new in this subsection.
Tuples
Rust |
Husht |
fn reverse(pair: (i32, bool)) -> (bool, i32) {
let (int_param, bool_param) = pair;
(bool_param, int_param)
}
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
fn main() {
// A tuple with a bunch of different types.
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64,
'a', true);
println!("Long tuple first value: {}", long_tuple.0);
println!("Long tuple second value: {}", long_tuple.1);
let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);
println!("tuple of tuples: {:?}", tuple_of_tuples);
let pair = (1, true);
println!("Pair is {:?}", pair);
println!("The reversed pair is {:?}", reverse(pair));
// Comma required in one-element tuples:
println!("One element tuple: {:?}", (5u32,));
println!("Just an integer: {:?}", (5u32));
let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
println!("{:?}", matrix);
}
|
fn reverse((int_param, bool_param): (i32, bool)) -> (bool, i32)
(bool_param, int_param)
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
fn main()
// A tuple with a bunch of different types.
let long_tuple = (1u8, 2u16, 3u32, 4u64
-1i8, -2i16, -3i32, -4i64
0.1f32, 0.2f64,
'a', true)
println! "Long tuple first value: {}", long_tuple.0
println! "Long tuple second value: {}", long_tuple.1
let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16)
println! "tuple of tuples: {:?}", tuple_of_tuples
let pair = (1, true)
println! "Pair is {:?}", pair
println! "The reversed pair is {:?}", reverse pair
// Comma required in one-element tuples:
println! "One element tuple: {:?}", (5u32,)
println! "Just an integer: {:?}", (5u32)
let matrix = Matrix
1.1, 1.2
2.1, 2.2
println! "{:?}", matrix
|
Arrays and slices
Not really anything new in this subsection; we don't currently expect that Husht will make material changes in array/slice declaration or indexing.
Custom Types
Structures
Rust |
Husht |
#![allow(dead_code)]
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
struct Unit;
struct Pair(i32, f32);
struct Point {
x: f32,
y: f32,
}
struct Rectangle {
top_left: Point,
bottom_right: Point,
}
fn main() {
// Create struct with field init shorthand
let name = String::from("Peter");
let age = 27;
let peter = Person { name, age };
println!("{:?}", peter);
let point: Point = Point { x: 10.3, y: 0.4 };
let another_point: Point = Point { x: 5.2, y: 0.2 };
println!("point coordinates: ({}, {})", point.x, point.y);
let bottom_right = Point { x: 5.2, ..another_point };
println!("second point: ({}, {})", bottom_right.x, bottom_right.y);
// Destructure the point using a `let` binding
let Point { x: left_edge, y: top_edge } = point;
let _rectangle = Rectangle {
top_left: Point { x: left_edge, y: top_edge },
bottom_right: bottom_right,
};
let _unit = Unit;
let pair = Pair(1, 0.1);
println!("pair contains {:?} and {:?}", pair.0, pair.1);
// Destructure a tuple struct
let Pair(integer, decimal) = pair;
println!("pair contains {:?} and {:?}", integer, decimal);
}
|
#![allow(dead_code)]
#[derive(Debug)]
struct Person
name: String
age: u8
struct Unit
struct Pair(i32, f32)
struct Point x, y: f32
struct Rectangle
top_left, bottom_right: Point
fn main
// Create struct with field init shorthand
let name = s"Peter" //! Note s-string
let age = 27
let peter = Person name, age
println! "{:?}", peter
let point: Point = Point x: 10.3, y: 0.4
let another_point: Point = Point x: 5.2, y: 0.2
println! "point coordinates: ({}, {})", point.x, point.y
let bottom_right = Point x: 5.2, ..another_point
println! "second point: ({}, {})", bottom_right.x, bottom_right.y
// Destructure the point using a `let` binding
let Point x: left_edge, y: top_edge = point
let _rectangle = Rectangle
top_left: Point
x: left_edge, y: top_edge
bottom_right: bottom_right
let _unit = Unit
let pair = Pair 1, 0.1
println! "pair contains {:?} and {:?}", pair.0, pair.1
// Destructure a tuple struct
let Pair integer, decimal = pair
println! "pair contains {:?} and {:?}", integer, decimal
|
Enums
Rust |
Husht |
enum WebEvent {
// An `enum` variant may either be `unit-like`,
PageLoad,
PageUnload,
// like tuple structs,
KeyPress(char),
Paste(String),
// or like structures.
Click { x: i64, y: i64 },
}
fn inspect(event: WebEvent) {
match event {
WebEvent::PageLoad => println!("page loaded"),
WebEvent::PageUnload => println!("page unloaded"),
// Destructure `c` from inside the `enum` variant.
WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
WebEvent::Paste(s) => println!("pasted \"{}\".", s),
// Destructure `Click` into `x` and `y`.
WebEvent::Click { x, y } => {
println!("clicked at x={}, y={}.", x, y);
},
}
}
fn main() {
let pressed = WebEvent::KeyPress('x');
let pasted = WebEvent::Paste("my text".to_owned());
let click = WebEvent::Click { x: 20, y: 80 };
let load = WebEvent::PageLoad;
let unload = WebEvent::PageUnload;
inspect(pressed);
inspect(pasted);
inspect(click);
inspect(load);
inspect(unload);
}
|
enum WebEvent
// An `enum` variant may either be `unit-like`,
PageLoad,
PageUnload,
// like tuple structs,
KeyPress(char),
Paste(String),
// or like structures.
Click
x, y: i64
fn inspect(event: WebEvent)
match event //! Note variant auto-import
PageLoad => println! "page loaded"
PageUnload => println! "page unloaded"
// Destructure `c` from inside the `enum` variant.
KeyPress c => println! "pressed '{}'.", c
Paste s => println! "pasted \"{}\".", s
// Destructure `Click` into `x` and `y`.
Click x, y =>
println! "clicked at x={}, y={}.", x, y
fn main
let pressed = WebEvent::KeyPress 'x'
let pasted = WebEvent::Paste s"my text"
let click = WebEvent::Click x: 20, y: 80
let load = WebEvent::PageLoad
let unload = WebEvent::PageUnload
inspect pressed
inspect pasted
inspect click
inspect load
inspect unload
|
linked list
Rust |
Husht |
use crate::List::*;
enum List {
Cons(u32, Box<List>),
Nil,
}
impl List {
fn new() -> List {
Nil
}
fn prepend(self, elem: u32) -> List {
Cons(elem, Box::new(self))
}
fn len(&self) -> u32 {
match self {
Cons(_, tail) => 1 + tail.len(),
Nil => 0
}
}
fn stringify(&self) -> String {
match self {
Cons(head, tail) => {
format!("{}, {}", head, tail.stringify())
},
Nil => {
format!("Nil")
},
}
}
}
fn main() {
let mut list = List::new();
list = list.prepend(1);
list = list.prepend(2);
list = list.prepend(3);
println!("linked list has length: {}", list.len());
println!("{}", list.stringify());
}
|
// use crate::List::*; //! Unneeded: match auto-imports
enum List
Cons(u32, Box<List>)
Nil
impl List
fn new -> List Nil
fn prepend(self, elem: u32) -> List
Cons elem, Box::new self
fn len(&self) -> u32
match self
Cons _, tail => 1 + tail.len()
Nil => 0
fn stringify(&self) -> String
match self
Cons head, tail =>
format! "{}, {}", head, tail.stringify()
Nil =>
format! "Nil"
fn main
let mut list = List::new()
//! These calls could be chained, but they could have
//! been chained in Rust, and it's not reasonable to
//! expect Husht to detect chaining opportunities.
list = list.prepend(1)
list = list.prepend(2)
list = list.prepend(3)
println! "linked list has length: {}", list.len()
println! "{}", list.stringify()
|
Constants
Not really anything new in this section.
Variable Bindings
Not really anything new here.
Mutability
Or here.
Scope and shadowing
Rust |
Husht |
fn main() {
let long_lived_binding = 1;
{
let short_lived_binding = 2;
println!("inner short: {}", short_lived_binding);
}
// Error! `short_lived_binding` doesn't exist here
println!("outer short: {}", short_lived_binding);
// FIXME ^ Comment out this line
println!("outer long: {}", long_lived_binding);
}
|
fn main
let long_lived_binding = 1
scope //! Husht needs a keyword; other choices exist
let short_lived_binding = 2
println! "inner short: {}", short_lived_binding
// Error! `short_lived_binding` doesn't exist here
println! "outer short: {}", short_lived_binding
// FIXME ^ Comment out this line
println! "outer long: {}", long_lived_binding
|
Declare first
Nothing here.
Freezing
Or here.
Types
Nothing new syntax-wise in this entire section.
Conversion
Or here, so far as I can see.
Expressions
Rust |
Husht |
fn main() {
let x = 5u32;
let y = {
let x_squared = x * x;
let x_cube = x_squared * x;
x_cube + x_squared + x
};
let z = {
// Final semicolon discards value; `z` ← `()`
2 * x;
};
println!("x is {:?}", x);
println!("y is {:?}", y);
println!("z is {:?}", z);
}
|
fn main
let x = 5u32
let y =
let x_squared = x * x
let x_cube = x_squared * x
x_cube + x_squared + x
//! Here we encounter two important Husht points.
//! (1) Since there is only a single expression
//! following the `let z=`, without the `scope`
//! keyword this would merely be `let z = 2 * x`
//! (2) The final semicolon is allowed and preserved
//! by Husht to suppress the return value from the
//! scope, but returning the last expression from a
//! scope is the default for Husht except in the final
//! statement of a function typed to return Unit
let z = scope
// Final semicolon discards value; `z` ← `()`
2 * x;
println! "x is {:?}", x
println! "y is {:?}", y
println! "z is {:?}", z
|
Flow of Control
if/else
Rust |
Husht |
fn main() {
let n = 5;
if n < 0 {
print!("{} is negative", n);
} else if n > 0 {
print!("{} is positive", n);
} else {
print!("{} is zero", n);
}
let big_n =
if n < 10 && n > -10 {
println!(", and is small, * 10");
// This expression returns an `i32`.
10 * n
} else {
println!(", and is big, / 2");
// So here must return `i32` as well.
n / 2
// TODO ^ Try inserting a semicolon.
};
// ^ Don't forget to put a semicolon here! All `let` bindings need it.
println!("{} -> {}", n, big_n);
}
|
fn main
let n = 5
//! Note for the "then"-clause to be on the same line
//! as the condition requires an explicit `then`
if n < 0
print! "{} is negative", n
else if n > 0 then print! "{} is positive", n
else print! "{} is zero", n
//! Note more literate logical operators
let big_n =
if n < 10 and n > -10
println! ", and is small, * 10"
// This expression returns an `i32`.
10 * n
else
println! ", and is big, / 2"
// So here must return `i32` as well.
n / 2
// TODO ^ Try inserting a semicolon.
// ^ Don't forget to put a semicolon here! All `let` bindings need it.
//! ^ Husht FTW!
println! "{} -> {}", n, big_n
|
loop
Rust |
Husht |
fn main() {
let mut count = 0u32;
println!("Let's count until infinity!");
loop {
count += 1;
if count == 3 {
println!("three");
continue;
}
println!("{}", count);
if count == 5 {
println!("OK, that's enough");
break;
}
}
}
|
fn main
let mut count = 0u32
println! "Let's count until infinity!"
loop
count += 1
if count == 3
println! "three"
continue
println! "{}", count
if count == 5
println! "OK, that's enough"
break
|
Nesting and labels
Rust |
Husht |
#![allow(unreachable_code, unused_labels)]
fn main() {
'outer: loop {
println!("Entered the outer loop");
'inner: loop {
println!("Entered the inner loop");
break 'outer;
}
println!("This point will never be reached");
}
println!("Exited the outer loop");
}
|
#![allow(unreachable_code, unused_labels)]
fn main
'outer loop
println! "Entered the outer loop"
'inner loop
println! "Entered the inner loop"
break 'outer
println! "This point will never be reached"
println! "Exited the outer loop"
|
Returning from loops
Rust |
Husht |
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
assert_eq!(result, 20);
}
|
fn main
let mut counter = 0
let result = loop
counter += 1
if counter == 10 then break counter * 2
assert_eq! result, 20
|
while
Rust |
Husht |
fn main() {
let mut n = 1;
while n < 21 {
match () {
_ if n % 15 == 0 => println!("fizzbuzz"),
_ if n % 3 == 0 => println!("fizz"),
_ if n % 5 == 0 => println!("buzz"),
_ => println!("{}", n)
}
n += 1;
}
}
|
fn main
let mut n = 1
while n < 21
cond
n % 15 == 0 => println! "fizzbuzz"
n % 3 == 0 => println! "fizz"
n % 5 == 0 => println! "buzz"
else println! "{}", n
n += 1
|
for loops
This subsection introduces the three ways of converting collections into iterators. For convenience, we combine them into a single example here. Note that we have changed the loop specifications in the examples on the Rust side, because it seems more Rust-idiomatic to (for example) iterate on a reference to a collection than to call .iter explicitly.
Rust |
Husht |
fn main() {
let mut names = vec!["Bob", "Frank", "Ferris"];
for name in &names {
match name {
&"Ferris" => println!("Rustacean alert!"),
_ => println!("Hello {}", name),
}
}
println!("names: {:?}", names);
for name in &mut names {
*name = match name {
&mut "Ferris" => "Rustacean alert!",
_ => "Hello",
}
}
println!("names: {:?}", names);
for name in names {
match name {
"Hello" => println!("Someone was normal"),
_ => println!("Warning: {}", name),
}
}
// names has moved here and is unusable:
// println!("names: {:?}", names); // compile error
}
|
fn main
let mut names = vec!["Bob", "Frank", "Ferris"]
for name in &names
match name
&"Ferris" => println! "Rustacean alert!"
_ => println! "Hello {}", name
println!("names: {:?}", names);
for name in &mut names
*name = match name
&mut "Ferris" => "Rustacean alert!"
_ => "Hello"
println! "names: {:?}", names
for name in names
match name
"Hello" => println! "Someone was normal"
_ => println! "Warning: {}", name
// names has moved here and is unusable:
// println!("names: {:?}", names); // compile error
|
match
There's not really much new Husht-syntax-wise in this section. However, it does raise the challenge of destructuring a nested struct. Suppose Foo has fields bar of type Bar and baz of type Baz, and further each of Bar and Baz have fields x and y. Then the full destructure of a Foo might look like:
let Foo bar: Bar x: x1, y: y1, baz: Baz x: x2, y: y2 = aFoo
Is this really parseable? It seems not; what if Bar also had a Baz field named baz? There's no way for the parser to tell short of analyzing the types. So it seems some braces or linebreaks are necessary. Husht will allow either of course. So you could write:
let Foo bar: Bar {x: x1, y: y1}, baz: Baz x: x2, y: y2 = aFoo
or
let Foo
bar: Bar x: x1, y: y1
baz: Baz x: x2, y: y2
= aFoo
as the spirit moves you.
if-let
It seems the only new point relevant to Husht that arises here is the need to try to do auto-import for destructuring if-let (and maybe just destructuring lets as well), so that if Foo is a enum with variants Bar and Baz, and a
is of type Foo, then you can write just if let Bar = a ...
rather than if let Foo::Bar = a ...
. (To be clear, the intention is to tightly scope these auto-imports so that the name Bar doesn't "leak" into the surrounding code from places in which there is a clear implication (such as destructuring a Foo) that they should be in scope.
let-else
while-let
Apparently nothing else new in these sections.
Functions
Methods
Doesn't seem to be anything new here, but ...
Closures
... this one appears to be a biggie. Rust's closure syntax is very unusual, and there's lots of commentary concerning it online. So this first example block shows perhaps the "ideal" way we would recast it. The thing is, I can't understand why it isn't already this way, so maybe we are going to run into parsing problems? If so, we may need to revisit the syntax here.
Rust |
Husht |
fn main() {
let outer_var = 42;
let closure_annotated = |i: i32| -> i32 { i + outer_var };
let closure_inferred = |i | i + outer_var ;
println!("closure_annotated: {}", closure_annotated(1));
println!("closure_inferred: {}", closure_inferred(1));
// Once closure's type has been inferred, it cannot be inferred again with another type.
//println!("cannot reuse closure_inferred with another type: {}", closure_inferred(42i64));
// TODO: uncomment the line above and see the compiler error.
let one = || 1;
println!("closure returning one: {}", one());
}
|
fn main
let outer_var = 42
let closure_annotated = i: i32 -> i32 => i + outer_var
let closure_inferred = i => i + outer_var
println! "closure_annotated: {}", closure_annotated 1
println! "closure_inferred: {}", closure_inferred 1
// Once closure's type has been inferred, it cannot be inferred again with another type.
//println! "cannot reuse closure_inferred with another type: {}", closure_inferred 42i64
// TODO: uncomment the line above and see the compiler error.
let one = () => 1 //! Need something to mark empty param list, could use || like Rust...
println! "closure returning one: {}", one()
|
Another consideration is whether we want to have a shorthand for non-closure anonymous inline functions (i.e. ones that are enforced not to capture any identifiers). If so, the simplest mechanism might just be to use another arrow, i.e. Husht could look like:
fn main
let anon_func = x --> x*x
println! "call unknown {}", anon_func 1.6
// Exactly the same except for function name:
fn named_func(x: f64) -> f64 x* x
println! "call named {}", named_func 1.6
// Arrow looks slightly funny with type annotations:
let another = x: i64 -> i64 --> x*x
// but not too bad I think
Of course, there's no real reason to implement that until/unless we actually want anonymous regular (non-closure) functions.
A final, quite major consideration is whether we want to have syntax for unary single-expression functions parallel to that in Civet. The &
symbol would not be appropriate for Husht, but a good choice might be $
since as far as I can tell, it's not used otherwise in Rust except for macro arguments, and it is the conventional "single parameter name for a throwaway unary function" in JavaScript. So in this scheme, closure_inferred
above would become just $ + outer_var
. Not sure what would be a good way to type-annotate this, possibly ($i32 + outer_var): i32
or maybe there just is no type-annotated single-argument shorthand. And we would have let square = $ * $
as a shorthand for let square = x => x*x
. This notation seems so productive that I am just going to presume we want to implement it, and write the rest of the examples in this section in this way when possible.
Capturing
Rust |
Husht |
fn main() {
use std::mem;
let consume = || {
println!("`movable`: {:?}", movable);
mem::drop(movable);
};
// `consume` consumes the variable so this can only be called once.
consume();
let haystack = vec![1, 2, 3];
let contains = move |needle| haystack.contains(needle);
println!("{}", contains(&1));
println!("{}", contains(&4));
}
|
fn main
use std::mem
let consume = () =>
println! "`movable`: {:?}", movable
mem::drop movable
// `consume` consumes the variable so this can only be called once.
consume()
let haystack = vec![1, 2, 3]
let contains = move needle => haystack.contains needle
println! "{}", contains(&1) //! That we need the & is Rust weirdoness
println! "{}", contains(&4)
|
There doesn't seem to be anything else syntactically relevant in the other subsubsections here, until we get to...
Examples in std
Iterator::any
Rust |
Husht |
pub trait Iterator {
type Item;
fn any<F>(&mut self, f: F) -> bool where
F: FnMut(Self::Item) -> bool;
}
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2));
println!("2 in vec2: {}", vec2.into_iter().any(|x| x == 2));
println!("vec1 len: {}", vec1.len());
println!("First element of vec1 is: {}", vec1[0]);
// `into_iter()` does move `vec2` and its elements, so they cannot be used again
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
println!("2 in array1: {}", array1.iter() .any(|&x| x == 2));
println!("2 in array2: {}", array2.into_iter().any(|x| x == 2));
}
|
pub trait Iterator
type Item
fn any<F>(&mut self, f: F) -> bool where
F: FnMut(Self::Item) -> bool //! Should we be able to drop the `Self::` here?
fn main
let vec1 = vec![1, 2, 3]
vec2 = vec![4, 5, 6]
//! Note use of fragment of loop construct to just get the corresponding iterator
println! "2 in vec1: {}", in &vec1.any *$ == 2 //! since iterator ...
//! ... returns references, we have to dereference the argument.
//! Alternatively , we could write `$ == &2`
println! "2 in vec2: {}", in vec2.any $ == 2
println! "vec1 len: {}", vec1.len()
println! "First element of vec1 is: {}", vec1[0]
// `into_iter()` does move `vec2` and its elements, so they cannot be used again
let array1 = [1, 2, 3]
array2 = [4, 5, 6]
println! "2 in array1: {}", in &array1.any $ == &2
println! "2 in array2: {}", in array2.any $ == 2
|
Searching through iterators
Rust |
Husht |
pub trait Iterator {
type Item;
fn find<P>(&mut self, predicate: P) -> Option<Self::Item> where
P: FnMut(&Self::Item) -> bool;
}
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
let mut iter = vec1.iter();
let mut into_iter = vec2.into_iter();
println!("Find 2 in vec1: {:?}", iter .find(|&&x| x == 2));
println!("Find 2 in vec2: {:?}", into_iter.find(| &x| x == 2));
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
println!("Find 2 in array1: {:?}", array1.iter() .find(|&&x| x == 2));
println!("Find 2 in array2: {:?}", array2.into_iter().find(|&x| x == 2));
}
|
pub trait Iterator
type Item
fn find<P>(&mut self, predicate: P) -> Option<Self::Item> where
P: FnMut(&Self::Item) -> bool
//! Again, sh/could we allow both `Self::` to be elided?
fn main
let vec1 = vec![1, 2, 3]
let vec2 = vec![4, 5, 6]
let mut iter = in &vec1
let mut into_iter = in vec2
println! "Find 2 in vec1: {:?}", iter .find *$ == &2
println! "Find 2 in vec2: {:?}", into_iter.find *$ == 2
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
println! "Find 2 in array1: {:?}", in &array1.find *$ == &2
println! "Find 2 in array2: {:?}", in array2.find *$ == 2
|
Higher order functions
Rust |
Husht |
fn is_odd(n: u32) -> bool {
n % 2 == 1
}
fn main() {
let upper = 1000;
// Imperative approach
let mut acc = 0;
for n in 0.. {
let n_squared = n * n;
if n_squared >= upper {
break;
} else if is_odd(n_squared) {
acc += n_squared;
}
}
println!("imperative style: {}", acc);
// Functional approach
let sum_of_squared_odd_numbers: u32 =
(0..).map(|n| n * n)
.take_while(|&n_squared| n_squared < upper)
.filter(|&n_squared| is_odd(n_squared))
.sum();
println!("functional style: {}", sum_of_squared_odd_numbers);
}
|
// The below will actually make a closure
// that captures nothing, not a function
// as on the left; do we care?
let is_odd = $ % 2 == 1
fn main
let upper = 1000
// Imperative approach
let mut acc = 0
for n in 0..
let n_squared = n * n
if n_squared >= upper then break
else if is_odd n_squared
acc += n_squared
println! "imperative style: {}", acc
// Functional approach
let sum_of_squared_odd_numbers: u32 =
(0..).map $ * $
.take_while $ < &upper
.filter is_odd *$
.sum()
println! "functional style: {}", sum_of_squared_odd_numbers
|
Diverging functions
Rust |
Husht |
fn main() {
fn sum_odd_numbers(up_to: u32) -> u32 {
let mut acc = 0;
for i in 0..up_to {
let addition: u32 = match i%2 == 1 {
true => i,
false => continue,
};
acc += addition;
}
acc
}
println!("Sum of odd numbers up to 9 (excluding): {}",
sum_odd_numbers(9)
);
}
|
fn main
fn sum_odd_numbers(up_to: u32) -> u32
let mut acc = 0
for i in 0..up_to
let addition: u32 = match i%2 == 1
true => i
false => continue
acc += addition
acc
println!
"Sum of odd numbers up to 9 (excluding): {}"
sum_odd_numbers 9
|