当前位置: 首页 > wzjs >正文

做网站是买服务器还是买主机汕头cms模板建站

做网站是买服务器还是买主机,汕头cms模板建站,手机建站平台哪个便宜,简洁大气公司网站前言 【Tauri2】004——run函数的简单介绍(2)-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146512646?spm1001.2014.3001.5502 前面介绍了run函数,接下来介绍这个属性tauri::command,被这个属性修饰的函数,可以被注册为通…

前言

【Tauri2】004——run函数的简单介绍(2)-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146512646?spm=1001.2014.3001.5502

前面介绍了run函数,接下来介绍这个属性tauri::command,被这个属性修饰的函数,可以被注册为通信函数。invoke也一起介绍。

代码如下

#[tauri::command]
fn greet(name: &str) -> String {format!("Hello, {}! You've been greeted from Rust!", name)
}

正文

简单地一次通信

上面greet函数的意思是

接受参数name,返回字符串。

尝试发送消息,运行pnpm run tauri dev

输入123

 显示了Hello, 123! You've been greeted from Rust!

而和greet函数返回的内容一致,完成了通信。

在前端代码中,可以发现这样一行代码

   await invoke("greet", { name })

 其中第一个参数是字符串,而这个字符串恰好也是Rust的通信函数greet

第二个参数是name,而这个name恰好是greet函数的参数。

有点意思

发现

先暂时说一些其他东西。

笔者希望打个断点,可以调试代码,说实话,Tauri中使用了许多的宏

而宏是在编译的早期,对Tauri使用的依赖进行打断点,或者修改源码,感觉没有什么用,很苦恼,后来我明白了,Tauri进行了build之后,修改项目(start),会在已经build好的基础上,进行build

如果调用cargo clean,修改源码,进行一些打印语句,需要从头开始build,很浪费时间,很慢。

笔者慢慢尝试和思考

在build后,target/tubug目录下

deps目录拥有许多东西,什么dll,什么exe,都在这里面,tauri的build后的依赖也都在里面。

 如果删除某个依赖,使用cargo build命令,不会从0开始build,而是从删除的依赖作为起点,开始build

这一点非常关键,既节约了时间,也可以查看build的产物,并且能够修改源码了,哈哈哈哈

开始

ctrl+左击command,这个属性的定义

#[proc_macro_attribute]
pub fn command(attributes: TokenStream, item: TokenStream) -> TokenStream {command::wrapper(attributes, item)
}

从proc_macro_attribute可以发现是属性宏,而且,这个属性定义在tauri-macros

而在tauri-macros,主要是对宏的操作,使用了两个关键的依赖,syn和quote。

继续点击wrapper中

pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream 

这个wrapper就是command实现功能的关键。

如何操作

笔者第一次build完成后,笔者进入target/debug/deps中

因为笔者知道是tauri-macros依赖,因此,笔者搜索tauri-macros,

经过多次的尝试后,发现

删除类型应用程序扩展,进行cargo build

就是从tauri-macros开始的,实际上可以全部删了。

pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream

首先,在源码增加一些打印语句,然后删除。

  let attr=attributes.clone();let items= item.clone();let mut attrs = parse_macro_input!(attributes as WrapperAttributes);let function = parse_macro_input!(item as ItemFn);let isStart = function.sig.ident == "greet";// 函数名叫greetif(isStart){println!("attributes: {}",attr);println!("______________________");println!("item: {}",items);println!("______________________");}

打包,看看attributes和item是什么东西,结果如下

可以看出attribute是空的,而item就是command修饰的函数本身

代码模板

接下来看看,wrapper是如何处理这个函数的,在wrapper最后,可以看到代码模板。

中间过程都是些看不懂的操作,总之,一定是为代码模板服务的

因此,直接看代码模板

下面就是代码模板

  let result=quote!(#async_command_check#maybe_allow_unused#function#maybe_allow_unused#maybe_macro_export#[doc(hidden)]macro_rules! #wrapper {// double braces because the item is expected to be a block expression($path:path, $invoke:ident) => {{#[allow(unused_imports)]use #root::ipc::private::*;// prevent warnings when the body is a `compile_error!` or if the command has no arguments#[allow(unused_variables)]let #root::ipc::Invoke { message: #message, resolver: #resolver, acl: #acl } = $invoke;#maybe_span#body}};}// allow the macro to be resolved with the same path as the command function#[allow(unused_imports)]#visibility use #wrapper;);

添加打印语句,看看经过代码模板后的函数长什么样的

结果如下

macro_rules! __cmd__greet
{($path : path, $invoke : ident) =>{{#[allow(unused_imports)] use :: tauri :: ipc :: private :: * ;#[allow(unused_variables)] let :: tauri :: ipc :: Invoke{message : __tauri_message__, resolver : __tauri_resolver__,acl : __tauri_acl__} = $invoke; let result =$path(match :: tauri :: ipc :: CommandArg ::from_command(:: tauri :: ipc :: CommandItem{plugin : :: core :: option :: Option :: None, name :stringify! (greet), key : "name", message : &__tauri_message__, acl : & __tauri_acl__,}){Ok(arg) => arg, Err(err) =>{ __tauri_resolver__.invoke_error(err); return true },}); let kind = (& result).blocking_kind();kind.block(result, __tauri_resolver__); return true;}};
} #[allow(unused_imports)] use __cmd__greet;

这段代码,笔者也是感到非常迷惑。


解释代码

尽力尝试一下,首先

macro_rules! __cmd__greet

这是定义了一个声明宏

Macros By Example - The Rust Referencehttps://rustwiki.org/en/reference/macros-by-example.html而且,声明宏的名字是__cmd__greet,而greet的函数的名字。

build后在RustRover中可以看到


 ($path : path, $invoke : ident)

$path:路径,很明显,是指函数的路径,即crate::greet

$invoke:是ident对象,这个和前端的invoke函数,笔者直觉判断,必然是有关系的。

#[allow(unused_imports)] use :: tauri :: ipc :: private :: * ;
#[allow(unused_variables)] let :: tauri :: ipc :: Invoke

这两行就很简单,前面的两个#,第一个的意思是允许未使用的导入,后面是导入的东西,第二个的意思是允许未使用的变量Invoke

看看这个Invoke到底是什么

代码如下

#[default_runtime(crate::Wry, wry)]
pub struct Invoke<R: Runtime> {/// The message passed.pub message: InvokeMessage<R>,/// The resolver of the message.pub resolver: InvokeResolver<R>,/// Resolved ACL for this IPC invoke.pub acl: Option<Vec<ResolvedCommand>>,
}

先不管, 继续往下看

     {message : __tauri_message__, resolver : __tauri_resolver__,acl : __tauri_acl__} = $invoke

 这个$invoke,不就是前面宏的参数吗,前面加个{},再加上面的定义,很明显地断言

解包。

let result =$path(match :: tauri :: ipc :: CommandArg ::from_command(:: tauri :: ipc :: CommandItem{plugin : :: core :: option :: Option :: None, name :stringify! (greet), key : "name", message : &__tauri_message__, acl : & __tauri_acl__,}){Ok(arg) => arg, Err(err) =>{ __tauri_resolver__.invoke_error(err); return true },}); 

乍一看,这里感觉很复杂,慢慢看

首先,可以发现match,这是Rust中都关键字,再结合下面的Ok和Err,可以判断代码就是match,处理Option类型或者Result,简写一下

let result =$path(match opt{Ok(arg) => arg, Err(err) => { __tauri_resolver__.invoke_error(err); return true },}); 

成功返回arg,其中的CommandItem比较有意思

plugin: ::core::option::Option::None,  //None的意思说明不是插件
name: stringify!(greet),     // greet是函数名,因此,把函数名变成字符串
key: "name",   // 参数name
message: &__tauri_message__, // 前端发送的原始消息{"name":"123"}
acl: &__tauri_acl__,  // 权限验证

stringify in std - Rusthttps://doc.rust-lang.org/std/macro.stringify.html

 查看一下CommandArg,

use tauri::ipc::CommandArg;
pub trait CommandArg<'de, R: Runtime>: Sized {/// Derives an instance of `Self` from the [`CommandItem`].////// If the derivation fails, the corresponding message will be rejected using [`InvokeMessage#reject`].fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError>;
}

这个from_command传入了一个CommandItem,返回Result

成功返回Self,失败报错

再看看CommandItem

pub struct CommandItem<'a, R: Runtime> {/// Name of the plugin if this command targets one.pub plugin: Option<&'static str>,/// The name of the command, e.g. `handler` on `#[command] fn handler(value: u64)`pub name: &'static str,/// The key of the command item, e.g. `value` on `#[command] fn handler(value: u64)`pub key: &'static str,/// The [`InvokeMessage`] that was passed to this command.pub message: &'a InvokeMessage<R>,/// The resolved ACL for this command.pub acl: &'a Option<Vec<ResolvedCommand>>,
}

和刚刚看到的参数一样。

from_command成功返回Self,那么可以推断Ok(arg),这个arg就是Self,

而这个Self是什么?暂时不知道

后面Ok(arg)=>arg

再经过$path(arg)返回给result。

而$path可以认为是greet

那么

$path(arg)  不就是调用函数  greet(arg) 

原来如此。在这里居然调用了通信函数,笔者明白了哈哈哈哈哈

所以,这个Self,在这个greet函数里面是指String,这是参数

let kind = (& result).blocking_kind();

kind的英文翻译是 种类。

取了对result的一个引用,blocking_kind是判断异步还是同步

 kind.block(result, __tauri_resolver__); return true;

处理结果,__tauri_resolver__返回给前端,返回true。


最后

#[allow(unused_imports)] use __cmd__greet;

 不必细说。


简单看看invoke在前端的定义

再来看看invoke的定义,使用的TS

declare function invoke<T>(cmd: string, args?: InvokeArgs, options?: InvokeOptions): Promise<T>;
interface InvokeOptions {headers: Headers | Record<string, string>;
}

 从前面Invoke的定义,发现message是InvokeMessage

代码如下

pub struct InvokeMessage<R: Runtime> {/// The webview that received the invoke message.pub(crate) webview: Webview<R>,/// Application managed state.pub(crate) state: Arc<StateManager>,/// The IPC command.pub(crate) command: String,/// The JSON argument passed on the invoke message.pub(crate) payload: InvokeBody,/// The request headers.pub(crate) headers: HeaderMap,
}

因此,可以断言

第一次参数cmd,。正是对应tauri::ipc::Invoke::message::command

第二个参数 args。正是对应tauri::ipc::Invoke::message::payload

第三个参数option。正是对应tauri::ipc::Invoke::message::headers

返回值Promise。对应于Invoke::resolver

还有一个,笔者也不知道。

总结

前端通过invoke发送数据,Tauri在创建好的声明宏__cmd__greet中,调用了greet函数,结果返回给了前端。

原来如此。

这个宏中间肯定要进行数据转化。


文章转载自:

http://0yv6Khoo.Lqynj.cn
http://ucy0v9XX.Lqynj.cn
http://6jTtzKkf.Lqynj.cn
http://tDc5Md21.Lqynj.cn
http://HbT6un2j.Lqynj.cn
http://54QF90gc.Lqynj.cn
http://QEKM9GpF.Lqynj.cn
http://nWRTXZYQ.Lqynj.cn
http://Bptc5hnz.Lqynj.cn
http://H7yyG830.Lqynj.cn
http://ej12J2ZF.Lqynj.cn
http://5dKYmkXD.Lqynj.cn
http://aKmNwCnP.Lqynj.cn
http://ZBNVMWH4.Lqynj.cn
http://cNvUqPe3.Lqynj.cn
http://iZnORnoE.Lqynj.cn
http://21Mq5AqJ.Lqynj.cn
http://oDsqtl6y.Lqynj.cn
http://wpBngdIh.Lqynj.cn
http://SjT1ocaR.Lqynj.cn
http://VCdzMw7L.Lqynj.cn
http://IbqoMHyU.Lqynj.cn
http://hpnE5tng.Lqynj.cn
http://r7FSBRyN.Lqynj.cn
http://W7tOVlPZ.Lqynj.cn
http://WxaYyf8P.Lqynj.cn
http://R4HgaIkF.Lqynj.cn
http://SfGPYcM0.Lqynj.cn
http://qPxQMUoO.Lqynj.cn
http://W5enENYy.Lqynj.cn
http://www.dtcms.com/wzjs/743226.html

相关文章:

  • 公司网站建设推荐乐云seo企业做网站建设遇到的问题
  • 设计工作室的名字超级推荐的关键词怎么优化
  • 宁波网站建设团队佛山vi设计
  • 老干部局网站建设海淘网站入口
  • 各网站提交入口wordpress美图插件
  • 企业网站制作规划甘肃做网站的公司有哪些
  • 广州做企业网站的公司服务器域名是什么
  • 环保网站建设的目的公司网站制作导航
  • 做知识产权服务的网站排版设计
  • vi设计欣赏网站潍坊网站建设 诸城
  • 广西网站开发同ip网站有什么影响
  • 厦门建站程序wordpress排版工具
  • 莱州教育网站成都有哪些好玩的
  • 企业网站管理系统的运维服务芜湖哪里有做网站的
  • 网站建设需要什么人海口网站建设小强
  • 黄页网站推广服务html5彩票网站模板
  • 专业做外贸网站nginx wordpress 管理
  • 互联网站备案手续重庆新闻天天630
  • 接私活做网站设计深圳做男装什么网站容易找工
  • 陕西省和城乡建设厅网站wordpress带轮播企业站主题
  • 一个公网ip可以做几个网站二手书籍交易网站开发方式
  • 温州网站建设企业为客户网站做产品描述
  • 在您的网站首页添加标签最近三天的科技新闻
  • 网站宣传的方法有哪些公众号做视频网站
  • 跑腿网站建设营销网站的案例分析
  • 网站组织结构图网站服务费怎么做凭证
  • 做微电网的公司网站上海app开发定制
  • 网站开发服务器配置濮阳网站设计公司
  • 手机网站 分享按钮软件工程培训机构学费
  • 营销型 手机网站制作重庆网站开发哪家好