首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python中的类接口设计可以映射到Rust中吗?

Python中的类接口设计可以映射到Rust中吗?
EN

Stack Overflow用户
提问于 2018-07-26 06:35:45
回答 1查看 96关注 0票数 0

我在编写Python时经常使用的一种模式是使用仅类设计。我将创建一个只由classmethodstaticmethod方法组成的抽象基类。从这个基础上,我可以派生出具有这些方法的特定行为的子类。因为这些子类中的每个都有相同的接口,并且没有任何实例方法,所以我可以将类本身传递给客户端代码,而不是那些类的实例。

作为一个简单但真实/相关的示例,下面是我将如何处理对配置数据支持多种文件格式的需求:

代码语言:javascript
复制
import abc
import yaml
import json

class ConfigReader(abc.ABC):
    @classmethod
    def from_file_path(cls, path: str):
        with open(path) as fo:
            return cls.from_string(fo.read())

    @classmethod
    @abc.abstractmethod
    def from_string(cls, s: str):
        pass

class YamlConfigReader(ConfigReader):
    @classmethod
    def from_string(cls, s: str):
        return yaml.load(s)

class JsonConfigReader(ConfigReader):
    @classmethod
    def from_string(cls, s: str):
        return json.loads(s)

然后,客户端代码可以使用类本身来代替这些类的实例来执行配置解析:

代码语言:javascript
复制
import typing as tp

def read_config_file(path: str, config_reader: tp.Type[ConfigReader]):
    return config_reader.from_file_path(path)

print(read_config_file('config.yaml', YamlConfigReader))
print(read_config_file('config.json', JsonConfigReader))

我正在尝试在Rust中做类似上面的事情,但我似乎遇到了问题。我最初的方法使用了特征和相关的方法:

代码语言:javascript
复制
use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::io::Error;

pub trait ConfigReader {
    fn from_str<S: AsRef<str>>(s: S) -> Result<String, Error>;

    fn from_file<P: AsRef<Path>>(p: P) -> Result<String, Error> {
        let p = p.as_ref();
        let mut f = File::open(p)?;

        let mut buffer = String::new();
        f.read_to_string(&mut buffer)?;

        Self::from_str(buffer)
    }
}

pub struct YamlConfigReader;
pub struct JsonConfigReader;

impl ConfigReader for YamlConfigReader {
    fn from_str<S: AsRef<str>>(_s: S) -> Result<String, Error> {
        Ok("dummy".to_string())
    }
}

impl ConfigReader for JsonConfigReader {
    fn from_str<S: AsRef<str>>(_s: S) -> Result<String, Error> {
        Ok("dummy".to_string())
    }
}

fn read_config_file<P: AsRef<Path>>(p: P, config_reader: &ConfigReader) -> Result<String, Error> {
    config_reader.from_file(p)
}

fn main() {}

(playground)

这给了我一个错误:

代码语言:javascript
复制
error[E0038]: the trait `ConfigReader` cannot be made into an object
  --> src/main.rs:37:1
   |
37 | fn read_config_file<P: AsRef<Path>>(p: P, config_reader: &ConfigReader) -> Result<String, Error> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ConfigReader` cannot be made into an object
   |
   = note: method `from_str` has no receiver
   = note: method `from_file` has no receiver

这种模式在Rust中可能吗?如果没有,我可以用什么方法来模拟这种解耦的、模块化的、无状态接口的行为呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-26 06:44:05

在Rust中,您可以将类型参数视为类型参数:

代码语言:javascript
复制
fn read_config_file<P: AsRef<Path>, C: ConfigReader>(p: P) -> Result<String, Error> {
    C::from_file(p)
}

这限制了此类构造的动态性。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51528599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档