【问题标题】:Why Rust reset some variables after a loop?为什么 Rust 在循环后会重置一些变量?
【发布时间】:2020-12-24 22:34:16
【问题描述】:

我前段时间读完了 Rust 编程语言,为了自学 Rust,我正在创建一个简单的 http-server。

在用于解析&[u8] 并创建HttpRequest 对象的函数中,我注意到应该解析标头的循环实际上并未更新用于跟踪解析状态的某些变量:

pub fn parse_request(buffer: &[u8]) -> Result<HttpRequest, &'static str> {
    let (mut line, mut curr_req_reader_pos) = next_req_line(buffer, 0);

    let (method, path, version) = parse_method_path_and_version(&line)?;

    let (line, curr_req_reader_pos) = next_req_line(buffer, curr_req_reader_pos);
    //eprintln!("--- got next line: {}, {} ---", curr_req_reader_pos, String::from_utf8_lossy(line));
    let mut headers = vec![];
    let mut lel = 0;
    while line.len() > 0 {
        //eprintln!("LOOP");
        let header = parse_header(&line);
        eprintln!("--- parsed header: {} ---", String::from_utf8_lossy(line));
        headers.push(header);
        let (line, curr_req_reader_pos) = next_req_line(buffer, curr_req_reader_pos);
        //eprintln!("--- got next line: {}, {} ---", curr_req_reader_pos, String::from_utf8_lossy(line));
        let (line, curr_req_reader_pos) = next_req_line(buffer, curr_req_reader_pos);
        //eprintln!("--- got next line: {}, {} ---", curr_req_reader_pos, String::from_utf8_lossy(line));
        //eprintln!("LOOP");
        lel += 10;
        //break;
    }

    let (line, curr_req_reader_pos) = next_req_line(buffer, curr_req_reader_pos);
    //eprintln!("--- got next line: {}, {} ---", curr_req_reader_pos, String::from_utf8_lossy(line));
    //eprintln!("{}", lel);

    let has_body;
    match method.as_ref() {
        "POST" | "PUT" | "PATCH" => has_body = true,
        _ => has_body = true
    };

    let body;
    if has_body {
        let (line, curr_req_reader_pos) = next_req_line(buffer, curr_req_reader_pos);
        body = String::from_utf8_lossy(line).to_string();
    } else  {
        body = String::new();
    }

    Ok(HttpRequest {
        method,
        path,
        version,
        headers,
        has_body,
        body
    })
}

每种方法也有测试:

#[test]
fn test_next_req_line() {
    let req = "GET / HTTP/1.1\r\nContent-Length: 3\r\n\r\n\r\n\r\nlel".as_bytes();

    let (mut lel, mut pos) = next_req_line(req, 0);
    assert_eq!("GET / HTTP/1.1", String::from_utf8_lossy(lel));
    assert!(lel.len() > 0);
    assert_eq!(16, pos);

    let (lel, pos) = next_req_line(req, pos);
    assert_eq!("Content-Length: 3", String::from_utf8_lossy(lel));
    assert!(lel.len() > 0);
    assert_eq!(35, pos);

    let (lel, pos) = next_req_line(req, pos);
    assert_eq!("", String::from_utf8_lossy(lel));
    assert!(lel.len() == 0);
    assert_eq!(37, pos);

    let (lel, pos) = next_req_line(req, pos);
    assert_eq!("", String::from_utf8_lossy(lel));
    assert!(lel.len() == 0);

    let (lel, pos) = next_req_line(req, pos);
    assert_eq!("", String::from_utf8_lossy(lel));
    assert!(lel.len() == 0);

    let (lel, pos) = next_req_line(req, pos);
    assert_eq!("lel", String::from_utf8_lossy(lel));
    assert!(lel.len() == 3);
}

    #[test]
    fn test_parse_request() {
        let mut request = String::from("GET / HTTP/1.1\r\n");
        request.push_str("Content-Length: 3\r\n");
        request.push_str("\r\n");
        request.push_str("lel");
        let request = request.as_bytes();

        match parse_request(&request) {
            Ok(http_request) => {
                assert_eq!(http_request.method, "GET");
                assert_eq!(http_request.path, "/");
                assert_eq!(http_request.version, "HTTP/1.1");
            },
            Err(_) => {
                println!("Failed");
            }
        }
    }

注释行只是为了显示正在发生的事情,这就是我看到这个输出的地方:


    Finished test [unoptimized + debuginfo] target(s) in 0.53s
     Running target/debug/deps/rweb-6bbc2a3130f7e3d9

running 4 tests
test http::testing::test_next_req_line ... ok
test http::testing::test_parse_header ... ok
test http::testing::test_parse_method_path_and_version ... ok
--- parsed method path version  ---
--- got next line: 35, Content-Length: 3 ---
LOOP
--- parsed header: Content-Length: 3 ---
--- got next line: 37,  ---
--- got next line: 39, lel ---
LOOP
--- got next line: 37,  ---
10
test http::testing::test_parse_request ... ok

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

似乎while 循环没有重新分配linecurr_req_reader_pos 变量,但对我来说,期望循环会更新这些变量并解析每个标头是完全合理的。然而,它在循环之外完美地工作,正如任何人在测试中看到的那样。

根据我目前对 Rust 的理解,我无法弄清楚为什么会发生这种情况,为什么会发生这种情况?

【问题讨论】:

  • 您不是在循环中“重新分配”变量,而是创建新变量来暂时遮蔽外部变量,然后在迭代结束时超出范围。

标签: testing rust


【解决方案1】:

您不是在循环中“重新分配”变量,而是创建新变量来暂时遮蔽外部变量,然后在迭代结束时超出范围。

下面是关于简化伪代码的说明:

let x0 = 0
{
    let x1 = x0 + 1 // original x gets shadowed, x = 1
    let x2 = x1 + 1 // x1 gets shadowed, x = 2
} // both x1 and x2 go out of scope
let x1 = x0 + 1 // x = 1

【讨论】:

  • 是的。摆脱循环中的“让”。让我们在内部范围内创建一个同名的新变量。正如答案所解释的,这是“阴影”。要重新分配,请执行“x = SOMETHING”
猜你喜欢
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 2019-12-20
  • 2018-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多