跳到主要内容

OpcUaNodeId — 强类型 NodeId

概述

OPC UA 节点 ID 默认用字符串编码 ("ns=2;s=Foo")。OpcUaNodeId 是不可变 enum + struct, 显式带 namespace / id_type / identifier。

对应规范段: Part 6 §5.2.2。

API

成员类别读写说明
OpcUaNodeId::NULLconst空哨兵
OpcUaNodeId::from_numeric(ns, id)工厂数字型
OpcUaNodeId::from_string(ns, id)工厂字符串型
OpcUaNodeId::from_guid(ns, uuid)工厂GUID 型
OpcUaNodeId::from_opaque(ns, bytes)工厂不透明型
OpcUaNodeId::parse(s)静态解析, 返回 Result<Self, ParseError>
OpcUaNodeId::try_parse(s)静态等价 parse, 显式名
nid.to_string() / format!("{}", nid)序列化 (impl Display)
nid.namespace_index() / id_type() / identifier() / is_null()方法字段

相关结构:

pub enum NodeIdType {
Numeric = 0, // 编码 i=, u32
String = 1, // 编码 s=, UTF-8
Guid = 2, // 编码 g=, {xxxx-...}
Opaque = 3, // 编码 b=, base64
}

代码示例

use opcua::{OpcUaNodeId, NodeIdType};
use uuid::Uuid;

// 1) 工厂
let n1 = OpcUaNodeId::from_numeric(0, 84); // i=84
let n2 = OpcUaNodeId::from_string(2, "Boiler1.Temp");
let n3 = OpcUaNodeId::from_guid(3, Uuid::new_v4());
let n4 = OpcUaNodeId::from_opaque(4, vec![1, 2, 3]);

// 2) 解析
let n5 = OpcUaNodeId::parse("ns=2;s=Demo.Tag")?;
println!("ns={}, type={:?}", n5.namespace_index(), n5.id_type());

match OpcUaNodeId::try_parse("ns=99;i=foo") {
Ok(n) => println!("ok"),
Err(_) => println!("invalid"),
}

// 3) 序列化
let s = n2.to_string(); // "ns=2;s=Boiler1.Temp"

// 4) 与 SDK 互转
let dv = ua.read(&n2.to_string(), AttributeId::Value)?;

// 5) HashMap key (derive Hash, PartialEq, Eq)
use std::collections::HashMap;
let mut dict: HashMap<OpcUaNodeId, String> = HashMap::new();
dict.insert(n2.clone(), "锅炉一温度".into());

// 6) Null
println!("{}", OpcUaNodeId::NULL.is_null()); // true

最佳实践

  • 配置文件存字符串, 加载用 parse
  • 代码内部用强类型
  • Numeric 优先 (u32 比较快)
  • 用户输入用 try_parse (Result<Self, _>) 而非 panic

跨语言对照

C#PythonJavaC++RustC
OpcUaNodeIdOpcUaNodeIdOpcUaNodeIdOpcUaNodeIdOpcUaNodeIdDarraUa_NodeId
ParseparseparseParseparseDarraUa_NodeId_Parse
FromNumericfrom_numericfromNumericFromNumericfrom_numericDarraUa_NodeId_FromNumeric

下一步