2022-11-12:以下rust语言代码中,结构体S实现了crate::T1::T2的方法,如何获取方法列表?

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"

执行结果如下:

在这里插入图片描述

本作品采用《CC 协议》,转载必须注明作者和本文链接
微信公众号:福大大架构师每日一题。最新面试题,涉及golang,rust,mysql,redis,云原生,算法,分布式,网络,操作系统。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
470
粉丝
21
喜欢
37
收藏
22
排名:457
访问:1.9 万
私信
所有博文
社区赞助商