GithubHelp home page GithubHelp logo

Comments (8)

BurntSushi avatar BurntSushi commented on June 2, 2024 1

I copied your code from your link, but it compiles and runs just fine. Can you show me the exact code you're using that is giving you an error? It's otherwise hard to help.

from advent-of-code.

BurntSushi avatar BurntSushi commented on June 2, 2024 1

Hmm, well, part1 can be defined as fn part1(slice: &[T]) and then you can call it like part(&vector) where vector has type Vec<T>. But part1 then cannot mutate it. So you could define part1 as fn part1(slice: &mut [T]), which you can then sort, but that mutates the original vector. In other words, "I want to sort the vector in part1 without copying" and "I do not want to mutate the original vector" are mutually incompatible goals. This isn't just a Rust limitation; this is a limitation in general. You can't ever do that. Remember, if you have a Vec<Foo>, then that isn't a sequence of pointers to Foo. It's a contiguous sequence of Foo laid out in memory, side by side. If you want to be able to create a new vector that you can then mutate without literally copying the contents of Foo, then you need to introduce a layer of indirection such as Vec<Box<Foo>> or Vec<Rc<Foo>>.

from advent-of-code.

fabienjuif avatar fabienjuif commented on June 2, 2024

I just try to erase my file, and copy paste the file I linked, and I have the compilation error I just past before :(

I don't understand how it works on your side!

➜  day4 git:(borrow) rustc --version
rustc 1.30.1 (1433507eb 2018-11-07)
➜  day4 git:(borrow) cargo --version
cargo 1.30.0 (a1a4ad372 2018-11-02)
➜  day4 git:(borrow) cat src/main.rs
extern crate chrono;
extern crate regex;

use std::fs;
use regex::Regex;
use std::collections::HashMap;
use chrono::prelude::*;

const FILE_NAME: &str = "./input.txt";

struct Record {
    guard_id: String,
    date_time: DateTime<Utc>,
    fulldate: String,
    // date: String,
    // hour: String,
    minute: String,
    description: String,
}

struct Guard {
    id: String,
    minutes: Vec<(i64, i64)>,
    most_minute_asleep: (i64, i64),
    total_asleep: i64,
}

fn get_guards() {
    let content = fs::read_to_string(FILE_NAME).unwrap();
    let re = Regex::new(r"\[(\d+-\d+-\d+) (\d+):(\d+)\]( Guard #)?(\d+)? (.*)").unwrap();
    let mut records: Vec<Record> = Vec::new();

    for line in content.lines() {
        match re.captures(line) {
            Some(captures) => {
                let date = captures.get(1).unwrap().as_str().to_string();
                let hour = captures.get(2).unwrap().as_str().to_string();
                let minute = captures.get(3).unwrap().as_str().to_string();
                let fulldate = format!("{}T{}:{}:00Z", date, hour, minute);
                let description = captures.get(6).unwrap().as_str().to_string();
                let guard_id = match captures.get(5) {
                    Some(matcher) => matcher.as_str().to_string(),
                    None => String::from("")
                };
                let date_time = fulldate.parse::<DateTime<Utc>>().unwrap();

                records.push(Record {
                    guard_id,
                    date_time,
                    fulldate,
                    // date,
                    // hour,
                    minute,
                    description,
                });
            },
            None => {}
        }
    }

    records.sort_by(|record_a, record_b| record_a.date_time.cmp(&record_b.date_time));
    println!("records size: {}", records.len());

    let mut guards: HashMap<String, Guard> = HashMap::new();
    let mut current_guard: &mut Guard = &mut Guard { id: String::from(""), minutes: Vec::new(), most_minute_asleep: (0, 0), total_asleep: 0 };
    let mut last_date_time = Utc::now();
    let mut last_minute = String::from("");
    let mut minutes: HashMap<i64, i64> = HashMap::new();
    let mut sorted_minutes = Vec::new();

    for record in records {
        let Record { guard_id, date_time, description, minute, .. } = record;

        if !guard_id.is_empty() { // empty guard_id means we are changing guard
            current_guard = guards.entry(guard_id.clone()).or_insert(Guard {
                id: guard_id.clone(),
                minutes: Vec::new(),
                most_minute_asleep: (0, 0),
                total_asleep: 0,
            });

            for (minute, times) in minutes.iter() {
                sorted_minutes.push((minute.clone(), times.clone()));
            }
            sorted_minutes.sort_by(|minute_a, minute_b| minute_b.1.cmp(&minute_a.1));

            current_guard.minutes = sorted_minutes.drain(..).collect();
            current_guard.most_minute_asleep = match current_guard.minutes.get(0) {
                Some(value) => value.clone(),
                None => (0, 0)
            };

            minutes.clear();
            sorted_minutes.clear();
        }

        if description == "falls asleep" {
            last_date_time = date_time.clone();
            last_minute = minute.clone();
        }

        if description == "wakes up" {
            current_guard.total_asleep += (date_time - last_date_time).num_minutes() + 1;

            let num_minutes = (date_time - last_date_time).num_minutes();

            for min in 0..num_minutes {
                *minutes.entry(last_minute.parse::<i64>().unwrap() + min).or_insert(0) += 1;
            }
        }
    }
}

fn main() {
    get_guards();
}
➜  day4 git:(borrow) cargo build
   Compiling day4 v0.1.0 (/Volumes/sensitive/work/advent-of-code-2018/day4)
error[E0499]: cannot borrow `guards` as mutable more than once at a time
   --> src/main.rs:75:29
    |
75  |             current_guard = guards.entry(guard_id.clone()).or_insert(G
uard {
    |                             ^^^^^^ mutable borrow starts here in previ
ous iteration of loop
...
112 | }
    | - mutable borrow ends here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.
error: Could not compile `day4`.

To learn more, run the command again with --verbose.

from advent-of-code.

BurntSushi avatar BurntSushi commented on June 2, 2024

Oh, you must not be using Rust 2018. On Rust 2018, your code compiles because of improvements to the borrow checker. That is, before the improvements, the borrow checker rejected more valid programs. You can use Rust 2018 by adding edition = "2018" to the [package] section of your Cargo.toml. For that, you'll need the latest version of stable Rust (1.31).

This is a good example of the nice additions that Rust 2018 brings. I don't see any tiny changes I can make to your code to make it work. Instead, it seems to require some restructuring. e.g., something like this:

extern crate chrono;
extern crate regex;

use std::fs;
use regex::Regex;
use std::collections::HashMap;
use chrono::prelude::*;

const FILE_NAME: &str = "./input.txt";

struct Record {
    guard_id: String,
    date_time: DateTime<Utc>,
    fulldate: String,
    // date: String,
    // hour: String,
    minute: String,
    description: String,
}

struct Guard {
    id: String,
    minutes: Vec<(i64, i64)>,
    most_minute_asleep: (i64, i64),
    total_asleep: i64,
}

fn get_guards() {
    let content = fs::read_to_string(FILE_NAME).unwrap();
    let re = Regex::new(r"\[(\d+-\d+-\d+) (\d+):(\d+)\]( Guard #)?(\d+)? (.*)").unwrap();
    let mut records: Vec<Record> = Vec::new();

    for line in content.lines() {
        match re.captures(line) {
            Some(captures) => {
                let date = captures.get(1).unwrap().as_str().to_string();
                let hour = captures.get(2).unwrap().as_str().to_string();
                let minute = captures.get(3).unwrap().as_str().to_string();
                let fulldate = format!("{}T{}:{}:00Z", date, hour, minute);
                let description = captures.get(6).unwrap().as_str().to_string();
                let guard_id = match captures.get(5) {
                    Some(matcher) => matcher.as_str().to_string(),
                    None => String::from("")
                };
                let date_time = fulldate.parse::<DateTime<Utc>>().unwrap();

                records.push(Record {
                    guard_id,
                    date_time,
                    fulldate,
                    // date,
                    // hour,
                    minute,
                    description,
                });
            },
            None => {}
        }
    }

    records.sort_by(|record_a, record_b| record_a.date_time.cmp(&record_b.date_time));
    println!("records size: {}", records.len());

    let mut guards: HashMap<String, Guard> = HashMap::new();
    // let mut current_guard: &mut Guard = &mut Guard { id: String::from(""), minutes: Vec::new(), most_minute_asleep: (0, 0), total_asleep: 0 };
    let mut current_guard_id = String::from("");
    let mut last_date_time = Utc::now();
    let mut last_minute = String::from("");
    let mut minutes: HashMap<i64, i64> = HashMap::new();
    let mut sorted_minutes = Vec::new();

    for record in records {
        let Record { guard_id, date_time, description, minute, .. } = record;

        if !guard_id.is_empty() { // empty guard_id means we are changing guard
            current_guard_id = guard_id.clone();
        }
        let mut current_guard = guards
            .entry(current_guard_id.clone())
            .or_insert(Guard {
                id: guard_id.clone(),
                minutes: Vec::new(),
                most_minute_asleep: (0, 0),
                total_asleep: 0,
            });

        if !guard_id.is_empty() { // empty guard_id means we are changing guard
            for (minute, times) in minutes.iter() {
                sorted_minutes.push((minute.clone(), times.clone()));
            }
            sorted_minutes.sort_by(|minute_a, minute_b| minute_b.1.cmp(&minute_a.1));

            current_guard.minutes = sorted_minutes.drain(..).collect();
            current_guard.most_minute_asleep = match current_guard.minutes.get(0) {
                Some(value) => value.clone(),
                None => (0, 0)
            };

            minutes.clear();
            sorted_minutes.clear();
        }

        if description == "falls asleep" {
            last_date_time = date_time.clone();
            last_minute = minute.clone();
        }

        if description == "wakes up" {
            current_guard.total_asleep += (date_time - last_date_time).num_minutes() + 1;

            let num_minutes = (date_time - last_date_time).num_minutes();

            for min in 0..num_minutes {
                *minutes.entry(last_minute.parse::<i64>().unwrap() + min).or_insert(0) += 1;
            }
        }
    }
}

fn main() {
    get_guards();
}

from advent-of-code.

fabienjuif avatar fabienjuif commented on June 2, 2024

Thank you!

With your review and this thread: https://www.reddit.com/r/rust/comments/5ny09j/tips_to_not_fight_the_borrow_checker/

I have something that works :)

I didn't know I have to pass in "2018" version, thank you.
In the meantime it helps me understand the langage better :)

I updated my code as described here if you are curious: fabienjuif/advent-of-code-2018@dc8d762

For now I found Rust quite difficult to understand, for example I don't understand why I have to add "Clone" Trait to my structure when I just wanted my vectors to be copied (but not values) 🤔

Thank you (again) for helping me out ♥️

from advent-of-code.

BurntSushi avatar BurntSushi commented on June 2, 2024

For now I found Rust quite difficult to understand, for example I don't understand why I have to add "Clone" Trait to my structure when I just wanted my vectors to be copied (but not values)

This isn't necessarily Rust that's tripping you up, it's just that such an operation doesn't quite make sense. Vectors store their elements inline, such that a Vec<T> consistents of a pointer to a sequence of T values laid out sequentially in one contiguous block of memory. In order to copy that Vec<T>, you need to be able to copy all of the T values inside of it.

If you're looking to pass many pointers to that Vec<T> around, then you want to use &Vec<T>, of which as many such pointers as you like can be created. However, they are tracked by the borrow checker such that the lifetime of those pointers must be able to be tracked at compile time. If that's too onerous of a burden, then you can use Rc<Vec<T>> (or Arc<Vec<T>>) to represent shared ownership.

from advent-of-code.

fabienjuif avatar fabienjuif commented on June 2, 2024

What I wanted was to copy the vector into part1(), sort in a way into part1() that doesn't mutate the vector that was in main(), and do the same in part2() WITHOUT copying all its values.

fn main() {
  let vector = get_data(); // 1 000 000 elements
  println!("main, index0: {}", vector.get(0).unwrap()); // 1.

  part1(vector); // share access by a way I don't know

  println!("main, index0 (after): {}", vector.get(0).unwrap()); // 2.
} 

fn part1(let vector: Vec::<T>) {
  // ... vector.sort_by()
  println!("part1, index0: {}", vector.get(0).unwrap()); // 3.
}

I wanted to have 1. and 2. the same, but 3. could differ.
WITHOUT copying all vector values.
I wanted to only copy the pointers (to re-arrange them).

How would you do that?
Is it something that is in spirit of Rust?
Maybe I should dig slices?

Thank you a lot for your time 👍

from advent-of-code.

fabienjuif avatar fabienjuif commented on June 2, 2024

I think I understand the misconception that I have:

  • Vec stores Rectangle values ?
  • And I thank more about it: Vec stores Rectangle pointers.

Thank you @BurntSushi

from advent-of-code.

Related Issues (16)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.