这个Rust代码可以在没有“匹配”语句的情况下编写吗?

时间:2013-10-17 05:01:52

标签: sqlite rust rust-0.8

linuxfood has created bindings for sqlite3,我很感激。我刚开始学习Rust(0.8),我正在努力理解这段代码到底在做什么:

extern mod sqlite;

fn db() {

    let database =
        match sqlite::open("test.db") {
            Ok(db) => db,
            Err(e) => {
                println(fmt!("Error opening test.db: %?", e));
                return;
            }
        };

我基本上了解它在做什么。它试图获取数据库连接并测试错误。我不明白它是如何做到的。

为了更好地理解它,我想在没有match语句的情况下重写它,但我没有这方面的知识。那可能吗? sqlite::open()会返回两个变量,还是仅返回一个?

如果没有match语句,该示例如何以不同方式编写?我不是说这是必要的或可取的,但它可以帮助我学习这门语言。

4 个答案:

答案 0 :(得分:8)

外部语句是一个赋值,它将匹配表达式的值赋给database。匹配表达式取决于sqlite::open的返回值,该值可能是Result<T, E>类型(带有变体Ok(T)Err(E)的枚举)。如果它是Ok,则枚举变体有一个参数,匹配表达式将其解构为db并传回该值(因此它被赋值给变量database)。如果它是Err,则enum变体有一个带有错误对象的参数,该参数被打印并且函数返回。

如果不使用匹配语句,可以像下面那样编写(只是因为你明确要求不使用匹配 - 大多数人都会考虑这种错误的编码风格):

let res = sqlite::open("test.db");
if res.is_err() {
    println!("Error opening test.db: {:?}", res.unwrap_err());
    return;
}
let database = res.unwrap();

答案 1 :(得分:5)

我自己只是在学习Rust,但这是解决这个问题的另一种方法。

import io.dropwizard.lifecycle.Managed;
import java.util.concurrent.Future;
import com.codahale.metrics.health.HealthCheck;

public class ManagedBean extends HealthCheck implements Managed {

    private final String name;
    private final ManagedThreadPool threadPool;
    private final ApplicationProcessor processor;
    private Future<?> future; // HERE sonarqube complains..

    public ManagedBean( String name, ManagedThreadPool threadPool, ApplicationProcessor processor ) {
        this.name = name;
        this.threadPool = threadPool;
        this.processor = processor;
    }

    @Override
    public void start() throws Exception {
        future = threadPool.submit( processor );
    }

    @Override
    public void stop() throws Exception {
        if ( !future.isDone() ) {
            future.cancel( true );
        }
    }

    @Override
    protected Result check() throws Exception {
        return processor.getHealthCheck().execute();
    }

}

请参阅documentation about if let

答案 2 :(得分:4)

This function open returns SqliteResult<Database>;根据定义pub type SqliteResult<T> = Result<T, ResultCode>,即std::result::Result<Database, ResultCode>

Result是一个enum,你根本无法在不匹配的情况下访问枚举的变体:也就是说,这是唯一的方法。当然,你可能有方法来抽象匹配,但它们必须用匹配来实现。

你可以从结果文档中看到它确实有像is_err这样的方便方法,大概是这个(它不是这个,但足够接近):

fn is_err(&self) -> bool {
    match *self {
        Ok(_) => false,
        Err(_) => true,
    }
}

unwrap(再次只是近似):

fn unwrap(self) -> T {
    match self {
        Ok(t) => t,
        Err(e) => fail!(),
    }
}

如您所见,这些是通过匹配实现的。在你的这种情况下,使用匹配是编写此代码的最佳方式。

答案 3 :(得分:3)

sqlite::open()正在返回枚举。枚举在生锈方面略有不同,枚举的每个值都可以附加字段。
http://static.rust-lang.org/doc/0.8/tutorial.html#enums

因此,在这种情况下,SqliteResult枚举可以是OkErr,如果它是Ok那么它就会引用附加到它的数据库,如果它是Err然后它有错误详细信息。

使用C#或Java背景,您可以将SqliteResult视为OkErr继承的基类,每个基类都有自己的相关信息。在这种情况下,match子句只是检查类型以查看返回的子类型。我不会过于注重这个并行,尽管尝试这种语言之间的概念是一个坏主意。