Rust Trick

Table of Contents

1. Rust Trick

1.1. closure: borrowed value doesn't live long enough

use std::collections::HashMap;
struct Solution {}
impl Solution {
    pub fn number_of_boomerangs(points: Vec<Vec<i32>>) -> i32 {
        let n = points.len();
        let mut distance = vec![HashMap::new(); n];
        for i in 0..n {
            for j in i + 1..n {
                let (p1, p2) = (&points[i], &points[j]);
                let d = (p1[0] - p2[0]).pow(2) + (p1[1] - p2[1]).pow(2);
                *distance[i].entry(d).or_insert(0) += 1;
                *distance[j].entry(d).or_insert(0) += 1;
            }
        }
        // `m` does not live long enough.
        distance
            .into_iter()
            .flat_map(|m| m.values().map(|k| k * (k - 1)))
            .sum()
    }
}

fn main() {
    println!(
        "{:?}",
        Solution::number_of_boomerangs(vec![
            vec![0, 0],
            vec![1, 0],
            vec![-1, 0],
            vec![0, 1],
            vec![0, -1],
        ])
    );
}

1.1.1. 分析

只需考虑 closure 本身: |m| m.values().xxx

这里的 m 是一个值而不是引用, 所以它在 lifetime 为 closure 本身.但 m.values() 会返回一个 iter, 这个 iter 持有对 m 的引用.

因为 HashMap::values() 原型为 pub fn values(&self) -> Values<K, V>. 所以 closure 会返回 m 的引用, 导致出错.

简化的累似的问题为:

fn main() {
    let v = vec![1, 2, 3];
    v.into_iter().map(|x| &x);
}

1.1.2. 解决

// into_iter() 修改为 iter(), 使得 m 变为引用, 有更长的作用域
distance
    .iter()
    .flat_map(|m| m.values().map(|k| k * (k - 1)))
    .sum()

// 不要返回引用: m.values().xxx
distance
    .into_iter()
    .flat_map(|m| m.values().map(|k| k * (k - 1)).collect::<i32>())
    .sum()

Author: [email protected]
Date: 2019-02-23 Sat 00:00
Last updated: 2020-11-16 Mon 20:28

知识共享许可协议