I am currently exploring the wonders of Rust by rewriting exercises from A Tour of Go.
I understand both Go and Rust have different features, not everything is fully rewritable and I had my share of fighting the borrow checker. However I got to one fairly simple exercise, yet all solutions I come up with seem very... complex.
The Go Example
package main
import "fmt"
func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names) // [John Paul George Ringo]
a := names[0:2]
b := names[1:3]
fmt.Println(a, b) // [John Paul] [Paul George]
b[0] = "XXX"
fmt.Println(a, b) // [John XXX] [XXX George]
fmt.Println(names) // [John XXX George Ringo]
}
In Go we just create 2 slices do a mutation through one and we are done. We do some tradeoff of safety for simplicity thanks to the GC.
The Rust Example - #1
fn main() {
let mut names = ["John", "Paul", "George", "Ringo"];
println!("{:?}", names); // [John Paul George Ringo]
{
let a = &names[..2];
let b = &names[1..3];
println!("{:?} {:?}", a, b); // [John Paul] [Paul George]
}
{
// need a separate mutable slice identical to 'b'
let tmp = &mut names[1..3];
tmp[0] = "XXX";
}
{
// need to assign same variables just to print them out
let a = &names[..2];
let b = &names[1..3];
println!("{:?} {:?}", a, b); // [John XXX] [XXX George]
}
println!("{:?}", names); // [John XXX George Ringo]
}
This is as close to a one to one rewrite of the previous example as I can get, obviously this is far from optimal due to extra duplicity and overhead involved, so I created a second example.
The Rust Example - #2
fn slice_writer(arr: &[&str]) {
let a = &arr[..2];
let b = &arr[1..3];
println!("{:?} {:?}", a, b);
}
fn main() {
let mut names = ["John", "Paul", "George", "Ringo"];
println!("{:?}", names);
slice_writer(&names);
{
// still need to have the duplicity of '[1..3]'
let tmp = &mut names[1..3];
tmp[0] = "XXX";
}
slice_writer(&names);
println!("{:?}", names);
}
This feels really cumbersome to write; I need to create a separate function just to remove duplicity of assigning the same slices, a problem I shouldn't have in the first place. Rust creates all these safety measures but it either causes a degradation of performance as we need to create those same variables multiple times, clear them, hold the function in memory, etc. or I need to use some esoteric 'unsafe' procedures and what is the point of using the borrow checker then?
Summary
Am I missing something obvious here? What is the simple solution to this problem? Or is this how it is supposed to be done? In that case I can't imagine what it will be like writing something more massive than a single slice mutating program.
codereview.SE
. If you want to ask something about the borrow checker, you should (1.) edit your title to reflect that, and (2.) make sure your question is focused: questions like "what's the point of the borrow checker anyway?" are usually way too broad for StackOverflow. Thanks! - Lukas KalbertodtO(N)
vsO(N^2)
) or via measurement. clear them — I don't think there's any such activity here. hold the function in memory — it's likely the function is inlined, but the memory difference between the two will be negligible. - Shepmaster