面试题答案
一键面试函数调用顺序
在Rust中,逻辑与运算符&&
和逻辑或运算符||
都具有短路特性。
对于fn1() && fn2()
,会首先调用fn1()
。如果fn1()
返回true
,才会接着调用fn2()
;如果fn1()
返回false
,则fn2()
不会被调用。
可能出现的问题
- 共享状态问题:由于
fn2()
修改全局状态,如果多个线程同时执行fn1() && fn2()
这样的代码,可能会导致数据竞争。例如,一个线程在检查fn1()
为true
之后,还没来得及调用fn2()
时,另一个线程也检查fn1()
为true
并调用了fn2()
修改了全局状态,当第一个线程再调用fn2()
时,就可能基于已经被修改的状态进行操作,导致不可预期的结果。 - 错误处理问题:如果
fn2()
可能会发生错误,但由于逻辑与的短路特性,fn2()
可能不会被调用,从而使得相关错误不会被处理。
解决方案
- 处理共享状态问题:
- 使用互斥锁(Mutex):可以使用
std::sync::Mutex
来保护全局状态。例如:
- 使用互斥锁(Mutex):可以使用
use std::sync::{Arc, Mutex};
static GLOBAL_STATE: Arc<Mutex<i32>> = Arc::new(Mutex::new(0));
fn fn1() -> bool {
true
}
fn fn2() {
let mut state = GLOBAL_STATE.lock().unwrap();
*state += 1;
}
- **使用原子类型**:对于简单的全局状态,可以使用原子类型(如`std::sync::atomic::AtomicI32`),它们提供了原子操作,避免数据竞争。例如:
use std::sync::atomic::{AtomicI32, Ordering};
static GLOBAL_STATE: AtomicI32 = AtomicI32::new(0);
fn fn1() -> bool {
true
}
fn fn2() {
GLOBAL_STATE.fetch_add(1, Ordering::SeqCst);
}
- 处理错误处理问题:
- 将错误处理逻辑移到
fn1()
外部:例如,如果fn2()
返回Result
类型:
- 将错误处理逻辑移到
fn fn1() -> bool {
true
}
fn fn2() -> Result<(), &'static str> {
// 模拟可能的错误
Err("Some error")
}
fn main() {
if fn1() {
match fn2() {
Ok(_) => (),
Err(e) => eprintln!("Error: {}", e),
}
}
}
- **使用`and_then`方法(适用于`Result`类型)**:如果`fn1()`也返回`Result`类型,可以使用`and_then`方法链来处理:
fn fn1() -> Result<bool, &'static str> {
Ok(true)
}
fn fn2() -> Result<(), &'static str> {
// 模拟可能的错误
Err("Some error")
}
fn main() {
fn1().and_then(|res| {
if res {
fn2()
} else {
Ok(())
}
}).unwrap_or_else(|e| eprintln!("Error: {}", e));
}