2022-11-12:以下rust语言代码中,结构体S实现了crate::T1::T2的方法,如何获取方法列表?以下代码应该返回[“m1“,“m2“,“m5“],顺序不限。m3是S的方法,但并不属于c
2022-11-12:以下rust语言代码中,结构体S实现了crate::T1::T2的方法,如何获取方法列表?以下代码应该返回[“m1”,“m2”,“m5”],顺序不限。m3是S的方法,但并不属于crate::T1::T2的。m4也是S的方法,但这是实现T3的,也不属于crate::T1::T2的。
pub struct S;
impl crate::T1::T2 for S {
fn m1(&mut self){}
fn m2(&mut self){}
}
impl S {
fn m3(&mut self){}
}
impl T3 for S {
fn m4(&mut self){}
}
impl crate::T1::T2 for S {
fn m5(&mut self){}
}
答案2022-11-12:
要解析rust的代码,syn,quote,proc-macro2合理利用这三个库。
使用场景是写框架。
代码如下:
// main.rs文件内容如下:
use quote::quote;
use std::collections::HashSet;
use std::error::Error;
use syn::spanned::Spanned;
use syn::visit::Visit;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let content = include_str!("test.rs.txt");
let ast: syn::File = syn::parse_file(content)?;
let mut a = ImplVisitor::new("crate::T1::T2", "S");
a.visit_file(&ast);
println!("out_method_name_set = {:#?}", a.out_method_name_set);
Ok(())
}
// 遍历服务的方法
pub struct ImplMethodVisitor {
// 收集方法
pub out_method_name_set: HashSet<String>,
}
impl ImplMethodVisitor {
pub fn new() -> Self {
Self {
out_method_name_set: HashSet::new(),
}
}
}
impl<'ast> Visit<'ast> for ImplMethodVisitor {
fn visit_impl_item_method(&mut self, node: &'ast syn::ImplItemMethod) {
// 获取方法名
let method_a = &node.sig.ident;
let method = format!("{}", quote! {#method_a});
// 将方法保存起来
self.out_method_name_set.insert(method);
// Delegate to the default impl to visit any nested functions.
//visit::visit_impl_item_method(self, node);
}
}
// 遍历服务的实现
pub struct ImplVisitor {
// 接口名
pub interface_name: String,
// 服务名
pub service_name: String,
// 收集方法
pub out_method_name_set: HashSet<String>,
// 结束行
pub out_end_line: usize,
// 结束列
pub out_end_column: usize,
}
impl ImplVisitor {
pub fn new(interface_name: &str, service_name: &str) -> Self {
Self {
interface_name: String::from(interface_name),
service_name: String::from(service_name),
out_method_name_set: HashSet::new(),
out_end_line: 0,
out_end_column: 0,
}
}
}
impl<'ast> Visit<'ast> for ImplVisitor {
fn visit_item_impl(&mut self, node: &'ast syn::ItemImpl) {
// 获取服务名称
let service_a = node.self_ty.as_ref();
let mut service = String::new();
match service_a {
syn::Type::Path(service_b) => {
let mut ans = String::new();
for service_c in service_b.path.segments.iter() {
let service_d = service_c.ident.clone();
ans.push_str("::");
let aaa = format!("{}", quote! {#service_d});
ans.push_str(&aaa);
}
//println!("找到Service----{}",&ans[2..]);
service = String::from(&ans[2..]);
}
_ => {
//println!("没找到Service");
}
}
// 获取接口名称
let interface_a = &node.trait_;
let mut interface = String::new();
match interface_a {
Some(interface_b) => {
let interface_c = &interface_b.1;
let mut ans = String::new();
for interface_d in interface_c.segments.iter() {
let interface_e = &interface_d.ident;
ans.push_str("::");
let interface_f = format!("{}", quote! {#interface_e});
ans.push_str(&interface_f);
}
//println!("找到接口----{}",&ans[2..]);
interface = String::from(&ans[2..]);
}
_ => {
//println!("没找到接口");
}
}
if self.interface_name != interface {
//println!("接口不匹配");
return;
}
if self.service_name != service {
//println!("服务名称不匹配");
return;
}
// println!("接口名和服务名都匹配----{}----{}",interface,service);
// 修改结束索引
self.out_end_line = node.span().end().line - 1;
self.out_end_column = node.span().end().column - 1;
// 遍历方法
let mut mv = ImplMethodVisitor::new();
mv.visit_item_impl(node);
// 将方法保存起来
for m in mv.out_method_name_set.iter() {
self.out_method_name_set.insert(String::from(m));
}
// Delegate to the default impl to visit any nested functions.
//visit::visit_item_impl(self, node);
}
}
// test.rs.txt内容如下:
pub struct S;
impl crate::T1::T2 for S {
fn m1(&mut self){}
fn m2(&mut self){}
}
impl S {
fn m3(&mut self){}
}
impl T3 for S {
fn m4(&mut self){}
}
impl crate::T1::T2 for S {
fn m5(&mut self){}
}
# Cargo.toml内容如下:
[package]
name = "rust-ast"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0.66"
proc-macro2={ version = "1.0.47", features = ["span-locations"] }
syn = {version = "1.0",features=["full","extra-traits","visit"]}
quote = "1"
执行结果如下:

2022-11-12:以下rust语言代码中,结构体S实现了crate::T1::T2的方法,如何获取方法列表?以下代码应该返回[“m1“,“m2“,“m5“],顺序不限。m3是S的方法,但并不属于c的更多相关文章
- C语言中结构体对齐问题
C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...
- Go语言中结构体的使用-第2部分OOP
1 概述 结构体的基本语法请参见:Go语言中结构体的使用-第1部分结构体.结构体除了是一个复合数据之外,还用来做面向对象编程.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. ...
- 6. Go 语言中结构体的使用
1. 结构体的定义格式 在go语言中结果的定义格式如下: 123 type structName struct { filedList} 列子如下: 1234 type Person struct { ...
- C语言中结构体赋值问题的讨论
今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...
- C语言中结构体赋值问题的讨论(转载)
今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...
- Go语言中结构体的使用-第1部分结构体
1 概述 结构体是由成员构成的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性.结构体成员,也可称之为成员变量,字段,属性.属性要满足唯一性.结构体的概念在软件工程上 ...
- Go语言基础之结构体
Go语言基础之结构体 Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念.Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. 类型别名和自定义类型 自定义类型 在G ...
- C语言第九讲,结构体
C语言第九讲,结构体 一丶结构体的定义 在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据.结构体的定义形式为: struct 结构体名{ 结构体所包含的变量或数组 }; 结构体是一种 ...
- ndk学习之C语言基础复习----结构体、共用体与C++开端
自己实现sprintf功能: 关于C中的系统函数sprintf在上次[https://www.cnblogs.com/webor2006/p/7545627.html]学习中已经用到过了,这里再来回顾 ...
- GO学习-(13) Go语言基础之结构体
Go语言基础之结构体 Go语言中没有"类"的概念,也不支持"类"的继承等面向对象的概念.Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. ...
随机推荐
- Nginx配置ThinkPHP3.1的PATHINFO模式
location / { if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?$1 last; bre ...
- 9. 实现包括前端后台的预约洗狗功能 - 使用Power App处理预约信息 - 创建Power Canvas App并实现基础功能
Power Canvas App可以通过画布设计和构建业务应用,无需通过传统编写代码的形式来构建,通过将元素拖动到画布上来设计我们的Power Canvas APP,可以与Miceosoft和第三 ...
- HAL层分析
1. 安卓HAL模块基本 2. 定义hal层代码的5个特性 1)硬件抽象层具有与硬件的密切相关性. 2) 硬件抽象层具有与操作系统无关性. 3) 接口定义的功能应该包含硬件或者系统所需硬件支持的所有功 ...
- DVWA-XSS (Reflected) 反射性 XSS
反射性XSS,是非持久性,也是最常见的XSS,通过解析传入前段页面,常见为交互式输入框 LOW 审计源码 <?php // 发送请求头 header ("X-XSS-Protectio ...
- GUI编程--1
GUI编程--1 GUI是什么 (Graphical User Interface),即用户图形界面编程. 怎么玩 平时怎么运用 组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 1.简介 ...
- Kafka + SpringData + (Avro & String) 【Can't convert value of class java.lang.String】问题解决
[1]需求:Kafka 使用 Avero 反序列化时,同时需要对 String 类型的 JSON数据进行反序列化.AvroConfig的配置信息如下: 1 /** 2 * @author zzx 3 ...
- Unity C# IEnumrator 与 async 有的区别
前言 IEnumerator 和 async 是在 Unity 和 C# 中处理异步编程的两种不同方法.它们各自有不同的使用场景和优缺点. IEnumerator IEnumerator 是 C# 中 ...
- 集合-LinkedHashMap 源码详细分析(JDK1.8)
1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...
- 浅谈ChatGPT如何取代前端开发工程师
1.ChatGPT 是什么? ChatGPT 是一种基于深度学习的自然语言处理技术,它可以生成高质量的自然语言文本.该技术是由 OpenAI 团队 开发,旨在使计算机能够像人类一样理解和产生自然语言. ...
- 企业什么喜欢做电视看板,电视看板浏览网页的必备工具 电视看板浏览器 电视看板自动打开网页 电视看板必备APP
企业喜欢做电视看板主要是因为它可以提供以下几个方面的优势: 增强企业形象:电视看板可以将企业的信息和广告以更加生动.直观的方式呈现出来,提高企业形象和知名度. 提高工作效率:电视看板可以在企业内部作为 ...