【Tauri2】045——简单使用CommandArg

发布于:2025-05-16 ⋅ 阅读:(17) ⋅ 点赞:(0)

前言

前面在使用http插件的时候,使用了Channel提及了一个trait——CommandArg,这个trait还是很关键的。

【Tauri2】40——tauri-plugin-http-CSDN博客https://blog.csdn.net/qq_63401240/article/details/147705455?spm=1001.2014.3001.5501这篇就来看看CommandArg这个trait

从前面的文章中,可以知道,实现了这个trait,在通信函数中就可以自动获取,不需要从前端传入

比如AppHandle、Window、Webview等都可以从后端获取。

正文

看看这个trait的定义

pub trait CommandArg<'de, R: Runtime>: Sized {
  fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError>;
}

有生命周期,泛型R,泛型约束是Runtime。

要求实现 CommandArg 的类型是 Sized 的,即在编译时大小已知。

只有一个方法from_command,这个方法的参数的类型是CommandItem

返回 Result<Self, InvokeError>

总之,实现这个trait,必须要实现from_command这个方法。

因此,简单使用一下

使用

在src-tauri/src/com.rs文件中

定义一个类型User,为User实现这个trait。代码如下,

use serde::Serialize;
use tauri::ipc::{CommandArg, CommandItem, InvokeError};
use tauri::{Runtime};
#[derive(Serialize)]
pub struct User{
    pub id: u32,
    pub name: String,
}
impl<'de,R:Runtime> CommandArg<'de,R> for User {
    fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
        Ok(User {
            id: 1,
            name: "test".to_string(),
        })
    }
}

直接简单地返回一个User。

在通信函数中

#[command]
fn get_user(user: User)->User {
    user
}

注册通信函数。前端代码调用

    type User = {
        id: number;
        name: string;
    };  

    async function clicked() {
       let user=await invoke<User>("get_user");
       console.log(user);
       console.log("id 是",user.id);
       console.log("name 是",user.name);
    }

不需要传参。

结果如下

没问题。

这篇文章就写完了,感觉有点少。

搞复杂点

比如,可以类似于Channel,需要传入一个东西,比如id

修改代码,结果如下

    fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
        let name=command.name;
        let arg=command.key;
        let id: String =
            Deserialize::deserialize(command).map_err(|e| Error::InvalidArgs(name, arg, e))?;
        let user=User::from_str(&id)
            .map_err(|_| {
            InvokeError::from(format!(
                "User value `{id}`, expected a String id"
            ))});
        Ok(user?)
    }

笔者使用from_str这个方法,需要使用FromStr这个trait,即

use std::str::FromStr;
impl FromStr for User {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let user=User{
            id: s.parse().unwrap(),
            name: "6666".to_string(),
        };
        Ok(user)
    }
}

 此时,前端写法就变了

async function clicked() {
       let user=await invoke<User>("get_user",{"user":"1"});
       console.log(user);
       console.log("id 是",user.id);
       console.log("name 是",user.name);
    }

需要这个参数user,而且传一个String,

如果没有,报错如下

"invalid args `user` for command `get_user`:
 command get_user missing required key user"

 如果不是String

"invalid args `user` for command `get_user`:
 invalid type: integer `1`, expected a string"

就像是根据id查询实体。就这样吧 ,很简单。

调试from_command函数

看看里面发生了什么。随便找个地方打个断点

笔者打了两个断点,想看看command里面长什么样的 

 前端pnpm run dev运行,笔者后端在Rustrover中使用debug模式运行,在Rustrover中的debug模式,实际上就是使用了lldb这个调试器,

llvm/llvm-project: The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.https://github.com/llvm/llvm-project实际上,笔者下载llvm,可以使用lldb,笔者配置了环境变量

lldb  target/debug/start.exe

有报错,可以运行

在com.rs文件中26行设置断点

breakpoint set --file com.rs --line 26

 结果如下,效果不是很好

 没有rust插件,笔者lldb-rust也用不了,因为架构的原因。

因此,笔者使用RustRover中的debug模式。至于为什么RustRover中能使用,笔者也不理解。

看看command

有五个字段,plugin是None,name是&str,显而易见就是通信函数的名字——get_user

key就是其中参数的名字——user

acl笔者发现里面没有什么东西,说白了,没有初始化

长度是140698947526855,一看这个长度就不对劲,往里面看

其中pointer是NULL,因此,没有初始化。

message就比较多了

因此,笔者留到下一篇介绍,这里面有许多东西,先不慌。

走到下一个断点

看看 name

 p name

不用看都可以知道,就是get_user这个字符串

结果如下

(lldb) p name
(ref$<str$>) name = {
  data_ptr = 0x00007ff703d25678
  length = 8
}
(lldb) memory read 0x00007ff703d25678 -c 8
0x7ff703d25678: 67 65 74 5f 75 73 65 72                          get_user

没问题。 

看看arg

(lldb) p arg
(ref$<str$>) arg = {
  data_ptr = 0x00007ff703d25680
  length = 4
}
(lldb) memory read 0x00007ff703d25680 -c 4
0x7ff703d25680: 75 73 65 72                                      user

 没问题

按F8,步过,一直到id出现

(lldb) p id
(alloc::string::String) id = {
  vec = {
    buf = {
      inner = {
        ptr = {
          pointer = {
            pointer = 0x000001828380cb10
          }
          _marker = {}
        }
        cap = (__0 = 1)
        alloc = {}
      }
      _marker = {}
    }
    len = 1
  }
}

有地址,有长度

(lldb) memory read -c 1 0x000001828380cb10
0x1828380cb10: 31                                               1

 结果为1 ,没问题

看看user

往前走,一直到user出现

(lldb) p user
(core::result::Result<start::com::User,tauri::ipc::InvokeError>::Ok) user = {
  0 = {
    id = 1
    name = {
      vec = {
        buf = {
          inner = {
            ptr = {
              pointer = {
                pointer = 0x000002f6c9bf7d30
              }
              _marker = {}
            }
            cap = (__0 = 4)
            alloc = {}
          }
          _marker = {}
        }
        len = 4
      }
    }
  }
}

id为1,name有地址,有长度

(lldb) memory read -c 4 0x000002f6c9bf7d30
0x2f6c9bf7d30: 36 36 36 36                                      6666

没问题 

总结

对于CommandArg 具体怎么使用,看个人需求


网站公告

今日签到

点亮在社区的每一天
去签到