跳到主要内容

Safe API — 永不返回 Err 的变体

概述

Rust 默认就用 Result<T, OpcUaError> 处理失败。Safe 变体把 Err(OpcUaError) 折叠为 (StatusCode, T::default), 返回 tuple 而不是 Result, 让批量循环不必每条 ? 或 unwrap, 不打断执行流。

对应规范段: Browse Part 4 §5.8, Read §5.10.2, Write §5.10.4, Call §5.11.2, HistoryRead Part 11 §6.5。

API

方法类别读写说明
ua.browse_safe(node_id, filter)浏览返回 (StatusCode, Vec<OpcUaReference>)
ua.read_safe(node_id, attribute)返回 (StatusCode, Option<DataValue>)
ua.write_safe(node_id, value, attribute)返回 StatusCode
ua.call_safe(object_id, method_id, &inputs)方法返回 (StatusCode, Vec<Variant>)
ua.read_history_safe(node_id, t0, t1, max)历史返回 (StatusCode, Vec<DataValue>)

代码示例

use opcua::{DarraOpcUa, StatusCode, Variant, NodeClass, AttributeId};

let ua = DarraOpcUa::new("opc.tcp://localhost:4840")?;
ua.connect()?;

// 1) 浏览 - 节点删除不让全树报错
let (st, refs) = ua.browse_safe("ns=2;s=Boiler1", NodeClass::Unspecified);
if st != StatusCode::Good {
println!("Browse 失败 {:?}", st);
} else {
for r in &refs {
println!("{}", r.browse_name);
}
}

// 2) 批量轮询 - 单点失败不打断
for nid in &node_list {
let (rs, dv) = ua.read_safe(nid, AttributeId::Value);
match (rs, dv) {
(StatusCode::Good, Some(v)) => println!("{} = {:?}", nid, v.value),
_ => println!("{} = <{:?}>", nid, rs),
}
}

// 3) 批量下发参数
for (nid, val) in setpoints {
let rc = ua.write_safe(nid, Variant::from(val), AttributeId::Value);
if rc != StatusCode::Good { eprintln!("写 {} 失败 {:?}", nid, rc); }
}

// 4) 调用方法
let (cst, _outs) = ua.call_safe("ns=2;s=Robot", "ns=2;s=Robot.Home", &[]);
if cst != StatusCode::Good { eprintln!("Home 失败: {:?}", cst); }

// 5) 历史
let (hst, vals) = ua.read_history_safe("ns=2;s=Temp", t0, t1, 5000);

与重试机制的关系

普通 read/write/browse/call/read_history 内部都包了 retry_on_session_fault, session 级故障会自动重连一次。Safe 变体也受益于自动重连, 把"重连后仍失败"的 Err 折叠为 StatusCode。

最佳实践

  • UI 主线程一律用 Safe — ? 传播到 UI 任务会让线程退出
  • 批处理 / 巡检循环用 Safe
  • 业务关键路径仍用普通 Result 版本, 用 ? 显式错误传播

跨语言对照

C#PythonJavaC++RustC
BrowseSafebrowse_safebrowseSafeBrowseSafebrowse_safeDarraUa_Session_BrowseSafe
ReadSaferead_safereadSafeReadSaferead_safeDarraUa_Session_ReadSafe
WriteSafewrite_safewriteSafeWriteSafewrite_safeDarraUa_Session_WriteSafe
CallSafecall_safecallSafeCallSafecall_safeDarraUa_Session_CallSafe
ReadHistorySaferead_history_safereadHistorySafeReadHistorySaferead_history_safeDarraUa_Session_ReadHistorySafe

下一步