【问题标题】:How to match value of <T> in Box<T> that is attribute of a Struct?如何匹配作为 Struct 属性的 Box<T> 中的 <T> 的值?
【发布时间】:2022-01-21 05:39:46
【问题描述】:

我正在尝试使用sqlparser crate 解析一个简单的查询,但我被困在 BinaryOp 结构上,该结构的值是Expr enum,而结构本身包含Expr enum

我可以通过匹配来打印输出:

sqlparser::ast::Expr::BinaryOp{left:a , op: b , right: c} =&gt; println!("{:?}",a)

但是当我尝试从中获取 Expr 时,它会出现以下错误:

error[E0308]: mismatched types
  --> src/main.rs:41:57
   |
38 | ...                   BinaryOp{left:a , op: b , right: c} => match *a {
   |                                                                    --
   |                                                                    |
   |                                                                    this expression has type `Box<Expr>`
   |                                                                    help: consider dereferencing the boxed value: `**a`
...
41 | ...                       sqlparser::ast::Expr::CompoundIdentifier(w) => {},
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Box`, found enum `Expr`
   |
   = note: expected struct `Box<Expr>`
                found enum `Expr`

我认为这是取消引用的问题,但是即使我添加了取消引用 (*a),我也无法解决它。

完整代码在这里:

use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
use sqlparser::ast::Statement::Query;
use sqlparser::ast::SetExpr;
use sqlparser::ast::Expr::BinaryOp;



fn main() {
    let dialect = GenericDialect {}; // or AnsiDialect

    let sql = "SELECT a,b FROM table_1 T1 left join table_2 T2 on T1.z = T2.z";

    let ast = &Parser::parse_sql(&dialect, sql).unwrap()[0];

    if let Query(x) = ast {
        match &x.body {
            SetExpr::Select(s) => {let projection = &s.projection;
                                   let from = &s.from;
                                   //let group = &s.group_by;

                                   for p in projection {
                                       if let sqlparser::ast::SelectItem::UnnamedExpr(i) = p {
                                           match i {
                                                sqlparser::ast::Expr::Identifier(r) => println!("{:?}", r.value),
                                                _ => {},
                                           };
                                       }
                                   }

                                   for f in from {
                                       //println!("{:?}",f.relation);
                                       for j in &f.joins {
                                           match &j.join_operator {
                                            sqlparser::ast::JoinOperator::Inner(inj) => println!("inner join {:?}",inj),
                                            sqlparser::ast::JoinOperator::LeftOuter(lfj) => match lfj {
                                                sqlparser::ast::JoinConstraint::On(on) => match on {
                                                    BinaryOp{left:a , op: b , right: c} => match *a {
                                                    
                                                        
                                                        sqlparser::ast::Expr::CompoundIdentifier(w) => {},

                                                        _ => {}
                                                    },
                                                _ => {}
                                                },
                                                _ => {}
                                            },
                                            _ => {}
                                            }
                                        }
                                    }
            },                      
            _ => {}
        }
    }
}

  

如何从 BinaryOp 结构中获取装箱值?

谢谢。

【问题讨论】:

  • 样式注释: 以您的方式对齐代码会产生大量缩进,使您的代码不必要地难以阅读。在这一行:SetExpr::Select(s) =&gt; {,您可能希望跳到下一行,并将其余部分缩进您在代码中其他地方使用的标准 4 个空格。

标签: rust dereference


【解决方案1】:

变量a 的类型为&amp;Box&lt;Expr&gt;,因此当您取消引用它时,*a,它只会删除引用,只留下Box&lt;Expr&gt;。不幸的是,您无法对 Box 中的值进行模式匹配(请参阅 How to pattern match a Box to get a struct's attribute?),因此您必须再次取消引用它以获取 Expr

match **a {

但是,匹配臂会尝试将变量 w**a移动,这是不允许的,因为它位于共享引用后面。

您可以通过&amp;**a 引用Expr 或绑定到ref w 而不仅仅是w 来完全避免移动。如果这对你来说看起来有点像符号汤,另一种选择是使用a.as_ref()(通过AsRef trait)。

【讨论】:

  • 这完全正确,但我建议将&amp;**a 更改为a.as_ref()。结果是一样的(参见它的实现:doc.rust-lang.org/src/alloc/boxed.rs.html#1755-1759),但我认为后者更具可读性。
  • @PossiblyAShrub 感谢您的建议!我已更改我的建议以使用它而不是 Deref
猜你喜欢
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-31
  • 1970-01-01
  • 1970-01-01
  • 2021-04-03
相关资源
最近更新 更多