我在编写Python时经常使用的一种模式是使用仅类设计。我将创建一个只由classmethod
和staticmethod
方法组成的抽象基类。从这个基础上,我可以派生出具有这些方法的特定行为的子类。因为这些子类中的每个都有相同的接口,并且没有任何实例方法,所以我可以将类本身传递给客户端代码,而不是那些类的实例。
作为一个简单但真实/相关的示例,下面是我将如何处理对配置数据支持多种文件格式的需求:
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)
然后,客户端代码可以使用类本身来代替这些类的实例来执行配置解析:
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中做类似上面的事情,但我似乎遇到了问题。我最初的方法使用了特征和相关的方法:
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() {}
这给了我一个错误:
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中可能吗?如果没有,我可以用什么方法来模拟这种解耦的、模块化的、无状态接口的行为呢?
发布于 2018-07-26 06:44:05
在Rust中,您可以将类型参数视为类型参数:
fn read_config_file<P: AsRef<Path>, C: ConfigReader>(p: P) -> Result<String, Error> {
C::from_file(p)
}
这限制了此类构造的动态性。
https://stackoverflow.com/questions/51528599
复制相似问题