| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | Use the ? operator to unwrap infallible results. ? is used for error propagation in conjunction with the result and option types | 201204T163120Z | Aiden4 |
| nan | 220801T124532Z | mousetai | |
| nan | 240513T084122Z | mousetai | |
| nan | 240417T173802Z | ShadowRa | |
| nan | 240417T140656Z | ShadowRa | |
| nan | 200315T015036Z | JayXon | |
| nan | 240112T205829Z | mousetai | |
| nan | 220622T151938Z | mousetai | |
| nan | 220923T194211Z | naffetS | |
| nan | When using string formatting for example with print! | 190722T155710Z | ruohola |
| nan | 211218T125254Z | Ezhik | |
| nan | 211216T031117Z | alephalp | |
| nan | 211209T102730Z | Ezhik | |
| nan | 211204T074732Z | Ezhik | |
| nan | When working with strings with newlines in them | 190722T162447Z | ruohola |
| nan | 200804T074731Z | TehPers | |
| nan | 200731T200235Z | madlaina | |
| nan | 200226T045903Z | JayXon | |
| nan | 200108T020007Z | JayXon | |
| nan | 190804T082440Z | JayXon | |
| 000 | When using whole number floating point numbers | 190723T175201Z | ruohola |
| nan | 190515T202310Z | Maya | |
| nan | 180219T123306Z | null | |
| nan | 160224T212211Z | Doorknob | |
| 000 | If you need many mutable variables | 161109T070403Z | user6126 |
| nan | 160706T213349Z | raggy |
Use the ? operator to unwrap infallible results. ? is used for error propagation in conjunction with the result and option types, and per this meta post returning them with infallible results is a standard output method. For example, the following code summing the value of a string when interpreted in base a and b, with ?:
|s,a,b|Ok(i32::from_str_radix(s,a)?+i32::from_str_radix(s,b)?)
and without:
|s,a,b|i32::from_str_radix(s,a).unwrap()+i32::from_str_radix(s,b).unwrap()
As you can see, with ? it is much shorter, and it works with options as well, although often for smaller gains.
Get the nth element of a String or &str slice
In rust you can't directly index a string or slice. If you want to build a string from indexes of another string you would typically do this:
s.chars().nth(n).unwrap() // char
s.bytes().nth(n).unwrap() // u8
Shorter is this, but it will depend s so won't work if s is generated from a expression:
s.as_bytes()[n]as char // char, supports only single byte characters
s.as_bytes()[n] // u8
However, if you are ok with a &str (like if you want to collect into a String or concatenate with a existing String). This also supports only single byte characters.
&s[n..][..1] // &str
&s[n..=n] // &str, if `n` is a single variable or sufficiently short expression
If your expression is a literal you can use byte string instead to index it directly:
b"hello world"[n] // u8
b"hello world"[n]as char // char
Modifying the nth element of a String
If you need to make multiple modifications:
unsafe{s.as_mut_vec()}
Gives you an array that allows very compact manipulation of the string. The original string can still be accessed after the last use of the mutable slice eg. for printing.
This would obviously be a terrible idea outside of golfing.
If you don't need to convert it back afterwards you can just do
s.into_bytes()
A comparison of techniques
Consumes mean methods that take self so you won't be able to use the string again afterwards.
Note any method on &str can also be called on a String
Single Use
| Code | Bytes | on what type | Unicode Safe | Consumes | Return Type |
|---|---|---|---|---|---|
s.chars().nth(n).unwrap() |
25 | &str |
Yes | No | char |
s.bytes().nth(n).unwrap() |
25 | &str |
No | No | u8 |
s.as_bytes()[n] |
15 | &str |
No | No | u8 |
&s[n..][..1] |
12 | &str |
No | No | &str |
&s[n..m] |
8 | &str |
No | No | &str |
unsafe{&s.as_bytes_mut()[n]} |
28 | &str |
No | No | &mut u8 |
unsafe{&s.as_mut_vec()[n]} |
26 | String |
No | No | &mut u8 |
Multi Use
For assignment to a variable if you need to take multiple slices and/or modifications. All of these return a format compatible with standard x[n] indexing.
| Code | Bytes | on what type | Unicode Safe | Consumes | Return Type |
|---|---|---|---|---|---|
s.as_bytes() |
12 | &str |
No | No | &[u8] |
s.chars().collect::Vec<_>() |
27 | &str |
Yes | No | Vec<char> |
unsafe{s.as_mut_bytes()} |
24 | &str |
No | No | &mut[u8] |
unsafe{s.as_mut_vec()} |
22 | String |
No | No | &mut Vec<u8> |
s.into_bytes() |
14 | String |
No | Yes | Vec<u8> |
Abuse reduce to do something special with the first element of an iterator
It's very inconvenient when the first element of an iterator is a special case, since all ways to deal with it are quite long.
You can use .next(): (~73 bytes)
let mut a=m.iter();let f=a.next().unwrap();for i in a{do_something(f,i)};
A lot shorter is using collect. Depending on what you need later with the array this may be the shortest choice. (~62 bytes)
let a:Vec<_>=m.collect();for i in a[1..]{do_something(a[0],i)}
However, a pro move I saw JoKing use was to use reduce. reduce already handles the first case special so all that is necessary is to just return it and don't modify it. This is (~36 bytes)
m.reduce(|f,a|{do_something(f,a);f})
Fallible unpacking can let you avoid filtering
If you have an iterable input, e.g. command-line arguments, where some values are known to be bad (the program name is not useful), and others can be split into multiple discrete values, the normal solution to loop over .skip(n) to bypass the bad values (e.g. .skip(1) to skip the program name in the arguments), split/collect the rest to a Vec, and use the values by indexing (unless they're referred to many times, it's not worth the cost to unpack). For example, imagine a program that receives four numbers at a time, comma-separated as command-line arguments, and must compute a value using each value individually. The simple solution (using the flat_map trick to avoid a level of unwraping or use of filter_map) is:
fn main(){
for a in std::env::args().skip(1){
let v:Vec<u32>=a.split(',').flat_map(str::parse).collect();
println!("{},{}",v[0]+v[1],v[2]+v[3])
}
}
And that's not bad. But the .skip(1) costs eight characters, and all the indexing costs 12 more, for a total of 20 characters we'd like to avoid. By using if let with slice-unpacking, we can imply the skip (assuming the program name isn't four numbers separated by embedded commas), and unpack to individual names, while still saving characters:
fn main(){
for a in std::env::args(){
let v:Vec<u32>=a.split(',').flat_map(str::parse).collect();
if let[m,n,o,p]=a.split(',').flat_map(str::parse).collect::<Vec<u32>>()[..]{
println!("{},{}",m+n,o+p)
}
}
}
The difference here is pretty trivial (the second version shaves 8+12=20 characters by avoiding .skip(1) and indexing four times, but it costs 18 more to wrap in if let, use a turbofish on collect instead of letting type-inference handle it the pattern itself is longer (let[m,n,o,p] vs. let v), and [..] is needed to convert from Vec to slice for the pattern matching.
But:
- Unpacking more values only costs two characters more per name, and saves three characters the first time said value is used, and if you need to use any given value more than once, it saves three more characters per use, etc.
- Frequently, type-inference can figure out the type of the matched values, and that will allow you to replace
iterator.collect::<Vec<u32>>()withVec::from_iter(iterator), saving eight characters and making it much quicker to reach the break even point.
If the iterator had no invalid values to skip, this wouldn't be worth as much (the .skip(1) is 40% of the savings here), but the general pattern can be useful even then if you have enough things to unpack, and use them often enough.
Use for loops or map to unwrap known Some/Ok values when ? isn't an option
When it's too expensive to declare a return value that would allow you to use ? to handle known Some/Ok values, and scope is not an issue, you can use the fact that Option and Result implement IntoIterator and a custom version of map to shorten variable declarations by using a for loop or their map method.
// Unwrapping Some
if let Some(x)=returnsoption(){} // Idiomatic fallible unwrap
let x=returnsoption().unwrap(); // Unconditional unwrap saves 1, and avoids nested scope
for x in returnsoption(){} // for loop saves five more, as cost of nested scope
returnsoption().map(|x|{}); // One longer with map if {} needed, and even nastier, scope-wise, and usually needs semi-colon
returnsoption().map(|x|); // Map one shorter when {} not needed and scope issues not a problem; can be two shorter in cases where semi-colon not needed
// Unwrapping Ok
if let Ok(x)=returnsresult(){} // Idiomatic fallible unwrap
let x=returnsresult().unwrap(); // Unconditional unwrap avoids nested scope, but costs 1
for x in returnsresult(){} // for loop saves four over next best option
returnsresult().map(|x|{}); // One longer with map if {} needed, and even nastier, scope-wise, and usually needs semi-colon
returnsresult().map(|x|); // Map one shorter when {} not needed and scope issues not a problem; can be two shorter in cases where semi-colon not needed
This even saves something when it means you need to use the turbofish, e.g., if the type of x can't be deduced:
let x:u32=s.parse().unwrap();
// vs.
for x in s.parse::<u32>(){}
saves two characters over let, even with the turbofish adding three characters, though map remains better if the scope issues aren't a problem:
// If scope issues aren't a problem, saves 2-4/3-5 (depending on need for semi-colon) more:
s.parse().map(|x:u32|{});
s.parse().map(|x:u32|);
All the uses of map will produce a compile-time warning due to the result being unused, so avoid them if that's a problem.
Replace all filter_map with flat_map
It works because:
filter_maptakes aFnMut(Self::Item) -> Option<B>flat_maptakes aFnMut(Self::Item) -> impl IntoIteratorOptionimplementsIntoIterator, which will return an iterator with one item forSomeand empty iterator forNone
Using slice patterns to get both an array and variables with the same value
It is a common trick to use array slicing to compactly assign many variables to the same value:
let[a,b,c]=[0;3]
// vs
let(a,b,c)=(0,0,0)
// or
let a=0;let b=0;let c=0;
I've never really seen this used on arrays, even though it also saves bytes there:
let[a,..@b]=[0;99]; // store "the rest" of the slice in b
// vs
let(a,b)=(0,[0;98]);
// or
let a=0;let b=[0;98];
Saves just one byte so may not be worth it if it increases the array size by one byte.
It works for mutable variables too:
let[mut v,mut u@..]=[0;99];
// vs
let(mut u,mut v)=(0,[0;98]);
if let can sometimes be shorter than match
Using match:
match a{M(v)=>expr,_=>other}
Using if let costs 2 bytes if there are only 2 branches and 1 is wildcard:
if let M(v)=a{expr}else{other}
More effective when your match needed {} anyways, like if the types don't match. For example:
match a{M(v)=>{expr;}_=>{other;}}
vs.:
if let M(v)=a{expr;}else{other;}
saves 1 byte.
Use @ to define multiple variables to the same value
@ is meant to define an alias for pattern matching (like destructuring an array but also getting the original array at the same time). But it works with plain variables too.
let a=2;let b=2; // 16 bytes
let(a,b)=(2,2); // 15 bytes
let a@b=2; // 10 bytes
It works in destructuring too:
let a=1;let b=1;let c=2;let d=2; // 32 bytes
let(a,b,c,d)=(1,1,2,2); // 23 bytes
let(a@b,c@d)=(1,2); // 19 bytes
When using string formatting for example with print!(), one can use both numbered and unnumbered formatters to save one byte per item to format:
Best shown with an example:
fn main() {
print!(
"{}{}{}. Yes, {0}{}{2}. All you other{1}{2}s are just imitating.",
"I'm", " Slim", " Shady", " the real",
);
}
Which outputs:
I'm Slim Shady. Yes, I'm the real Shady. All you other Slim Shadys are just imitating.
So the unnumbered formatters will get assigned to the items in order, this allows you to skip the index on them. Note that you can only use one unnumbered formatter per item to format, after that it will get used up.
scan and fold on Iterators can be used for stateful iteration
If your closure consists of variable declarations and iterating over something while keeping an internal state, you might be able to save some bytes by using scan or fold instead of a for loop:
|i:&str|{let(mut a,mut b,mut c)=(1,2,0);for x in i.chars(){/*AAA*/;/*BBB*/;c=/*CCC*/}c}
scan is good for handling many mutable variables, at the cost of some operations (such as assignment) requiring dereferencing with * and needing to collect the final value using a method like last:
|i:&str|i.chars().scan((1,2),|(a,b),x|{/*AAA*/;/*BBB*/;Some(/*CCC*/)}).last()
fold can also be used in a similar manner by passing values in the accumulator:
|i:&str|i.chars().fold((1,2,3),|(a,b,c),x|(/*AAA*/,/*BBB*/,/*CCC*/)).2
Do-while loops
Rust does not have a C-style do-while loop:
do{do_work();}while(condition);
But blocks are also expressions in Rust, so you can write:
while{do_work();condition}{}
(0..).scan can be shorter than std::iter::successors
If you want to make endless sequences that are based on previous state:
std::iter::successors(Some(a),|x,_|Some(/*something*/))
This will be shorter by a character:
(0..).scan(a,|x,_|{let y=*x;*x=/*something*/;Some(y)})
If you don't mind dropping the first case, it can be even shorter:
(0..).scan(a,|x,_|{*x=/*something*/;Some(*x)})
Loops are sometimes shorter than iterators
Even with the extra curly braces, in some cases it can be shorter to declare a mutable variable and use a loop instead of using Iterator methods.
For example, to do something with every third element of a slice and then return the last index:
|n:&[_]|{let mut i=0;while i<n.len(){println!("{}",n[i]);i+=3}i-3}
|n:&[_]|(0..=n.len()/3).map(|i|{println!("{}",n[i*3]);i*3}).last().unwrap()
When working with strings with newlines in them, you save one byte if you use a literal line break in the source code vs having a \n in the string and/or using println.
print!("Hello
World!
");
is 2 bytes less than:
println!("Hello\nWorld!");
Prefer todo! over panic!
todo! is shorter than panic! by 1 byte, so prefer to use it if you need to panic and exit the program. It's also shorter than print! by a byte, so it can shorten your program if you can output to stderr instead of stdout.
todo!("optional message for stderr")
Declare multiple variables using pattern matching
(Somewhat of an extension of https://codegolf.stackexchange.com/a/99124/97519)
Using multiple let statements:
let a=x;let b=y;
let a=x;let b=y;let c=z;
Using a tuple match saves 1 char for 2 variables and 3 more chars for ever variable after:
let(a,b)=(x,y);
let(a,b,c)=(x,y,z);
Similarly, you can use array patterns for initializing multiple mutable variables to the same value (this works with immutable variables too but is pretty useless):
let[mut a,mut b]=[x;2];
Use ..=
Replace all ..i+1 with ..=i to save 1 byte, works on both array index a[i..=i] and range (0..=n)
Use closure parameter to define variable instead of let
{let(a,b)=(A,B);X}
can be replaced by
(|a,b|X)(A,B)
to save 5 bytes if the type of a and b can be inferred, it usually works when they are integers or are passed to another function directly in X.
This works well on 2 or more variables, but for a single variable, this could still save 2 bytes if it allows you to get rid of the {}.
Converting &str to String
Never do these:
s.to_string() // 13 bytes
s.to_owned() // 12 bytes
This is always shorter:
s.repeat(1) // 11 bytes
If s is a string literal:
format!(s) // 10 bytes
For example: use format!("") instead of String::new() to save 2 bytes.
If type inference works:
s.into() // 8 bytes
When using whole number floating point numbers, you can omit the trailing .0 to save one byte.
let a=1.
is 1 byte less than:
let a=1.0
Skipping trailing semicolons
In functions returning (), where the last expression is also of type (), you don't need the trailing ;:
fn main(){print!("Hello, world!")}
Reading lines
After considering various things, I think that is generally the shortest way to retrieve a line. The line has a newline, it can be removed by trimming (.trim()) or if that cannot be done by slicing.
let y=&mut"".into();std::io::stdin().read_line(y);
For multiple lines, lines iterator can be used, the iterated line doesn't end in newline then. A glob import is needed to import BufRead, needed for lines to be available for StdinLock<'_> type.
use std::io::*;let y=stdin();y.lock().lines()
Use closures instead of functions
A closure:
|n|n+1
is shorter than a function:
fn f(n:i32)->i32{n+1}
Closures longer than one statement need braces but are still far shorter than a function.
If you need many mutable variables, it can waste a lot of space declaring them and initializing them, since each requires the mut keyword and you can't do anything like a=b=c=0. A solution then is to declare a mutable array
let mut a=[0;5];
You spend 3 extra bytes each time you use them vs. a normal variable:
a[0]+=1;
but it can often still be worth it.
Using tuples for the same trick is often an even better option:
let mut t=(1,4,"this", 0.5, 'c');
This has the advantage of saving a byte on each use vs. the array:
t.0=2
It also lets them be of different types. On the downside, it requires more characters to initialize.
Avoid .iter().enumerate()
Let's say you have some x that implements the IntoIterator Trait and you need to call a function f that takes the index of an element and a reference to it. The standard way of doing this is
x.iter().enumerate().map(f)
instead you can do
(0..).zip(x).map(f)
and save yourself not only the unusually long enumerate but also the call to iter!