-
All code must fit in an area of 69×22 cells.
-
Each example must begin (or very nearly so) with:
// This code is editable and runnable!
-
All examples must run on the playpen (and by extension, the
rust-lang.org
front page). -
Examples should avoid external crates, unless otherwise impossible.
-
-
Save DanielKeep/325960a142c0925a3da5 to your computer and use it in GitHub Desktop.
prospective r-l.o examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.sublime-workspace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
#![feature(libc)] | |
extern crate libc; | |
extern "C" { | |
// Bind directly to C functions, including varargs. | |
fn atoi(str: *const u8) -> libc::c_int; | |
fn printf(format: *const u8, ...) -> libc::c_int; | |
} | |
fn main() { | |
// All FFI is potentially unsafe. | |
unsafe { | |
let s = format!("{}\0", 42); | |
// Rust strings are UTF-8 (ptr, len); C strings are pointers | |
// with terminating `\0`s. We need to convert between them. | |
let s_ptr = s.as_bytes().as_ptr(); | |
// Beyond that, there is no overhead to calling C functions. | |
let i = atoi(s_ptr); | |
printf(b"`%s` (0x%x) -> %d\n\0".as_ptr(), s_ptr, s_ptr, i); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
fn main() { | |
let a = &7; | |
println!("inner result: {}", inner(a)); | |
} | |
// Returning pointers from functions is 100% safe in Rust. | |
fn min_ref<'x>(a: &'x i32, b: &'x i32) -> &'x i32 { | |
if *a < *b { a } else { b } | |
} | |
// Lifetime elision handles the annotations in this simple case. The | |
// lifetime of the output is assumed to be the same as the input. | |
fn inner(a: &i32) -> &i32 { | |
let b = &4; | |
let c = min_ref(a, b); | |
println!("min ref result: {}", *c); | |
// return c; | |
// ^ ERROR: borrowed value does not live long enough | |
// This is because `&4` only exists inside this function. | |
return a; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
// Note that circumventing the stdlib is still an unstable feature. | |
#![feature(lang_items, start, no_std, libc, core_slice_ext)] | |
#![no_std] | |
extern crate libc; | |
extern "C" { | |
fn printf(fmt: *const libc::c_char, ...) -> libc::c_int; | |
} | |
// Entry point for this program | |
#[start] | |
fn start(_argc: isize, _argv: *const *const u8) -> isize { | |
unsafe { | |
printf(b"Hello, World!\n\0".as_ptr() as *const _); | |
0 | |
} | |
} | |
// Functions required by the compiler, normally provided by libstd. | |
#[lang = "eh_personality"] extern fn eh_personality() {} | |
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
fn main() { | |
let s = String::from("an owned, heap-allocated string"); | |
{ | |
let substr = &s["an owned, ".len()..]; | |
println!("substr: {:?}", substr); | |
// let new_variable = s; | |
// ^ ERROR: cannot move out of `s` because it is borrowed | |
// Borrow of `s` ends here, which means... | |
} | |
// ...we can now move the contents of `s`. | |
let new_variable = s; | |
println!("new_variable: {:?}", new_variable); | |
// let yet_another_s = s; | |
// ^ ERROR: use of moved value: `s` | |
// Move semantics plus borrow checking prevents moving values | |
// that are still in use *and* unnecessary copying. | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
fn thing(n: i32) -> (i32, i32) { | |
// Patterns are everywhere! You can deconstruct on let bindings: | |
let (i, j) = (2*n, n/2); | |
(i + j, i - j) | |
} | |
// Argument bindings can pattern match, too: | |
fn some((a, b): (i32, i32)) -> Option<i32> { | |
match a - b { | |
// Patterns in `match` can have guard expressions: | |
x if x < 0 => None, | |
x => Some(x) | |
} | |
} | |
fn main() { | |
// There are also "refutable" matches, like `if let`: | |
if let Some(x) = some(thing(42)) { | |
println!("{}", x); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"folders": | |
[ | |
{ | |
"path": "." | |
} | |
], | |
"settings": | |
{ | |
"rulers": [69] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
use std::ops::Add; | |
// Even if this generic is in a library or *never* instantiated, the | |
// compiler can perform type checking and verify the code is correct. | |
fn add<T>(a: T, b: T) -> T | |
where T: Add<Output=T> { | |
a + b | |
} | |
// fn bad_add<T>(a: T, b: T) -> T { a + b } | |
// ^ ERROR: binary operation `+` cannot be applied to type `T` | |
// The generic function itself fails type checking, not at usage. | |
fn main() { | |
let _a: _ = add(3, 5i32); | |
let _b: u8 = add(b'0', 3); | |
let _c: _ = add(5.23f32, 0.2); | |
// let _d = add("hello,", " world!"); | |
// ^ ERROR: trait `Add` is not implemented for the type `&str` | |
// This error happens at usage, not within the generic function. | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
fn main() { | |
let s = "5 2 9"; | |
// The type of `nums` depends on the type of the closure, which | |
// depends on the result of `parse` which... we don't know yet. | |
let mut nums = s.split_whitespace().map(|w| w.parse().unwrap()); | |
// The type of `a`, `b`, and `c` *also* depend on the result of | |
// the `parse` calls, which we still don't know. | |
let a = nums.next().unwrap(); | |
let b = nums.next().unwrap(); | |
let c = nums.next().unwrap(); | |
// The compiler can now infer that `0`, `a`, `b`, and `c` *must* | |
// be the same type. Fallback permits it to assume this type is | |
// `i32`, which allows the compiler to infer all previously | |
// unspecified types. We have to "hint" that we want a `Vec` | |
// here, since many types can be `collect()`ed into. | |
let result: Vec<_> = (0..a).map(|e| e * b + c).collect(); | |
println!("{:?}", result); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cargo-deps: crossbeam="0.1.6" | |
// This code is editable and runnable! | |
extern crate crossbeam; | |
fn main() { | |
// Mutate a table *on the stack* across multiple threads, without | |
// data races or use-after-free, checked at compile time. | |
let mut table = [0; 100]; | |
crossbeam::scope(|scope| { | |
// Safely split the table into disjoint sub-slices. | |
for (i, slice) in table.chunks_mut(10).enumerate() { | |
// Spawn a thread within this scope, using the subslice. | |
scope.spawn(move || { | |
for e in slice { *e = i } | |
}); | |
} | |
// `crossbeam::scoped` makes sure all threads will join | |
// before leaving this scope. | |
}); | |
println!("{:?}", &table[..]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
use std::sync::{Arc, Mutex}; | |
fn main() { | |
let mut a = Box::new(42); // `a` gets *moved* into the thread. | |
let x = std::thread::spawn(move || { | |
*a = *a * 2; a // mutate a, then move it back out | |
}); | |
// Mutate an array shared between multiple threads. | |
let bs = Arc::new(Mutex::new([0, 0, 0])); | |
let mut ys = vec![]; | |
for is in vec![vec![1, 2], vec![2, 0, 2], vec![1, 0, 2, 1]] { | |
let bs = bs.clone(); // create new `Arc` handle. | |
ys.push(std::thread::spawn(move || { | |
for i in is { bs.lock().unwrap()[i] += 1; } | |
})); | |
} | |
let a = x.join().expect("thread panicked"); | |
for y in ys { y.join().expect("thread panicked"); } | |
println!("a: {:?}, bs: {:?}", a, bs); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
fn main() { | |
// Put an `i32` on the heap, then *move* it into the thread. | |
// There are no copies or sharing going on here. | |
let mut a = Box::new(0); | |
let x = std::thread::spawn(move || { | |
for i in 0..100_000 { *a += i } | |
a // pass the mutated `a` back to the main thread. | |
}); | |
// Also works for more complex types like dynamic strings. | |
let mut b = String::new(); | |
let y = std::thread::spawn(move || { | |
for _ in 0..200 { b.push_str("wasting cycles") } | |
b | |
}); | |
// Join the two threads, moving the results back. | |
let a = x.join().expect("thread panicked"); | |
let b = y.join().expect("thread panicked"); | |
println!("a: {:?}, b end: {:?}", a, &b[b.len()-11..]); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code is editable and runnable! | |
fn main() { | |
// Create a closure. There's no heap allocation involved. | |
let closure = || 2 + 2; | |
// In fact, with no captures, it requires no memory *at all*. | |
println!("size of closure: {}", std::mem::size_of_val(&closure)); | |
println!("static result: {}", two_times_static(&closure)); | |
println!("dynamic result: {}", two_times_dynamic(&closure)); | |
} | |
// `f()` can be inlined, eliminating abstraction cost. | |
fn two_times_static<F: Fn() -> i32>(f: &F) -> i32 { | |
2 * f() | |
} | |
// Or, we can dispatch at runtime using the same interface. | |
fn two_times_dynamic(f: &Fn() -> i32) -> i32 { | |
2 * f() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment