Why not work? about hashmap


#1
use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

fn main() {
	let path = Path::new("xx.log");
	println!("{:?}", path.display());
	let f = match File::open(&path) {
		Err(why) => panic!("fail{}", Error::description(&why)),
		Ok(file) => file
	};

	let mut count = 0u32;
	let mut map : HashMap<&str, i32> =  HashMap::new();

	let b = BufReader::new(f);
	for line in b.lines() {
	    let s = line.unwrap();
	    if s.find("REMOTING").is_some() {
	    	count +=1 ;
	    	let v : Vec<&str> = s.split_whitespace().collect();
	    	//println!("--{:?}", s);
	    	println!("**{} {} {}", v[0],v[1],v[2]);
	    	let k = v[0];
	    	
	    	match map.get(k) {
	    		Some(c) => map.insert(k, c+1),
	    		None => map.insert(k,1),
	    	};
	    }
	}
	println!("total count : {:?}", count);
}

show error:
main.rs:24:27: 24:28 error: s does not live long enough
main.rs:24 let v : Vec<&str> = s.split_whitespace().collect();


#2

If I understand correctly, the str references that you collect in v belong to s, i.e. they are pointers to the middle of the memory area allocated for s. Therefore, k is that too. The memory will disappear once s disappears, and that happens at each loop iteration.

But you try to insert k in map for longer than that. If Rust accepted that, that would leave dangling pointers in map.

I am rather new to the language, but I managed to get your example working by making k a string, i.e. let k = v[0].to_string() and changing the types (you can leave the compiler inger the type of the hash map) at a few places.

There is another problem though: map.get(&k) returns a reference; that means that as long as the reference exists, map is considered borrowed, and can not be modified. It can be worked around by computing the value to insert inside the match but calling map.insert(k, c + 1) only after.

With all that, I did manage to get the example to build.


#3

Just a small hint, on this forum, use triple backticks (```) before and after your code to have:

  1. proper indentation
  2. monospaced font
  3. syntax highlighting

This makes it more easy to read the code and might bring you more answers to your post.


#4

modify to : let k = v[0].to_string();

now –
main.rs:30:19: 30:22 error: cannot borrow map as mutable because it is also borrowed as immutable
main.rs:30 Some© => map.insert(k, c+1),


#5

:cold_sweat:


#6

I am pretty sure my first reply addressed that issue too.


#7

thanks!! it well work…

i try modify to:

  1. let k = v[0]; -> let k = v[0].to_string();
  2. match map.get(&k) { -> match map.get_mut(&k) {

#8

My solution was (from memory):

let current = match map.get(&k) {
    Some(c) => *c + 1,
    None => 0,
}

(humpf ten-year-old OCaml reflexes of putting -> for pattern matching)
… but if you can change the value in place with a mutable reference, that should be even more efficient since the hash lookup is done only once.