在Go中,您可以使用syms A Epsilon0 k1 k2 e s d R s f T c0 v0 v
An = 0.5*10^(-9);
Epsilon0n = 8.85*10^-12;
k1n = 10;
k2n = 10;
en = 1.6*10^-19;
sn = 1.8*10^(-9);%m gap size%
dn = 3*sn; % total distance
Rn = 1;
c0n=(An*Epsilon0n*k1n)/dn;
t1=0:0.1:5;
fn=1000;
v0n=7.5;
Tn=5/f;
vn=v0n*sin(2*3.14*fn*t1);
plot(t1,vn);
inits = 'q(0)=(20*10^(-20)),Q(0)=0';
[q,Q] = dsolve('Dq=((v/R)-(1/R)*(((d*q)+(s*Q))/(c0*d)))','DQ= (((q+Q)/(A*Epsilon0*k1))*s)',inits);
qn1=vpa(subs(q,{A,Epsilon0,k1,k2,e,s,d,R,c0}, {An,Epsilon0n,k1n,k2n,en,sn,dn,Rn,c0n}),3);
i=1;
while i<length(t1);
qn2(i)=subs(qn1, v, vn(i));
i=i+1;
end
t2=t1(1:50);
plot(t2,qn2)
关键字在当前函数返回时执行函数,类似于其他语言中的传统defer
关键字。无论整个功能体发生什么,这对于清理状态都很有用。以下是Go博客的一个例子:
finally
如何在Rust中实现此功能?我知道RAII,但在我的具体情况下,状态是在外部系统中。我正在编写一个将密钥写入键值存储的测试,我需要确保在测试结束时将其删除,无论测试中的断言是否会引起恐慌。
我找到了this Gist,但我不知道这是否是推荐方法。不安全的析构函数令人担忧。
Rust GitHub存储库中还有this issue,但它已经三年了,显然不再那么相关了。
答案 0 :(得分:20)
( e:不要错过bluss的答案以及下面的scopedguard箱子。)
通过在析构函数中运行代码(如链接到的defer!
宏)来实现此目的的正确方法。除了临时测试之外,我建议使用适当的析构函数编写句柄类型,例如:一个人通过其MutexGuard
类型(由std::sync::Mutex
返回)与lock
进行互动:无需在互斥锁本身上调用unlock
。 (显式句柄与析构函数方法也更灵活:它具有对数据的可变访问权限,而延迟方法可能无法实现,因为Rust具有强大的别名控制。)
在任何情况下,由于最近的变化,特别是pnkfelix的sound generic drop work,这个宏现在(很多!)得到了改善,这消除了#[unsafe_destructor]
的必要性。直接更新将是:
struct ScopeCall<F: FnMut()> {
c: F
}
impl<F: FnMut()> Drop for ScopeCall<F> {
fn drop(&mut self) {
(self.c)();
}
}
macro_rules! defer {
($e:expr) => (
let _scope_call = ScopeCall { c: || -> () { $e; } };
)
}
fn main() {
let x = 42u8;
defer!(println!("defer 1"));
defer!({
println!("defer 2");
println!("inside defer {}", x)
});
println!("normal execution {}", x);
}
输出:
normal execution 42
defer 2
inside defer 42
defer 1
虽然,它在语法上会更好:
macro_rules! expr { ($e: expr) => { $e } } // tt hack
macro_rules! defer {
($($data: tt)*) => (
let _scope_call = ScopeCall {
c: || -> () { expr!({ $($data)* }) }
};
)
}
(由于#5846,tt hack
是必要的。)
当存在多个语句时,使用泛型tt
(“标记树”)允许在没有内部{ ... }
的情况下调用它(即它的行为更像是“正常”控制流结构):
defer! {
println!("defer 2");
println!("inside defer {}", x)
}
此外,为了最大限度地提高延迟代码对捕获变量的作用,可以使用FnOnce
代替FnMut
:
struct ScopeCall<F: FnOnce()> {
c: Option<F>
}
impl<F: FnOnce()> Drop for ScopeCall<F> {
fn drop(&mut self) {
self.c.take().unwrap()()
}
}
这还需要围绕ScopeCall
的值构建Some
c
。 Option
舞蹈是必需的,因为调用FnOnce
会移动所有权,如果没有它,则无法从self: &mut ScopeCall<F>
后面移动。 (这样做没关系,因为析构函数只执行一次。)
总而言之:
struct ScopeCall<F: FnOnce()> {
c: Option<F>
}
impl<F: FnOnce()> Drop for ScopeCall<F> {
fn drop(&mut self) {
self.c.take().unwrap()()
}
}
macro_rules! expr { ($e: expr) => { $e } } // tt hack
macro_rules! defer {
($($data: tt)*) => (
let _scope_call = ScopeCall {
c: Some(|| -> () { expr!({ $($data)* }) })
};
)
}
fn main() {
let x = 42u8;
defer!(println!("defer 1"));
defer! {
println!("defer 2");
println!("inside defer {}", x)
}
println!("normal execution {}", x);
}
(与原始输出相同。)
答案 1 :(得分:11)
我使用以下内容作为范围保护。它使用Deref
特征来提供共享和优先级。可移动地访问受保护的值,而不将其移出(这将使警卫无效!)
我的用例是在程序退出时正确地重置终端,即使恐慌:
extern crate scopeguard;
use scopeguard::guard;
// ... terminal setup omitted ...
// Use a scope guard to restore terminal settings on quit/panic
let mut tty = guard(tty, |tty| {
// ... I use tty.write() here too ...
ts::tcsetattr(tty.as_raw_fd(), ts::TCSANOW, &old_attr).ok();
});
game_main(&mut tty).unwrap(); // Deref coercion magic hands off the inner &mut TTY pointer here.
模块scopeguard.rs:
use std::ops::{Deref, DerefMut};
pub struct Guard<T, F> where
F: FnMut(&mut T)
{
__dropfn: F,
__value: T,
}
pub fn guard<T, F>(v: T, dropfn: F) -> Guard<T, F> where
F: FnMut(&mut T)
{
Guard{__value: v, __dropfn: dropfn}
}
impl<T, F> Deref for Guard<T, F> where
F: FnMut(&mut T)
{
type Target = T;
fn deref(&self) -> &T
{
&self.__value
}
}
impl<T, F> DerefMut for Guard<T, F> where
F: FnMut(&mut T)
{
fn deref_mut(&mut self) -> &mut T
{
&mut self.__value
}
}
impl<T, F> Drop for Guard<T, F> where
F: FnMut(&mut T)
{
fn drop(&mut self) {
(self.__dropfn)(&mut self.__value)
}
}
这是现在的箱子scopeguard on crates.io.