我们如何允许符合预定义 API 的不同对象的组合?我尝试做的一种方法是通过使用特质中的特质但失败了,我的尝试
pub trait XAPI {
fn new(y: YAPI) -> Self;
}
pub trait YAPI {
fn new() -> Self;
}
pub struct X {
}
pub struct Y {
}
impl YAPI for Y{
fn new() -> Self {
Y {}
}
}
impl XAPI for X{
fn new(y: YAPI) -> Self {
X {}
}
}
这在 Rust 中可能吗?
Java 具体示例:
/* Online Java Compiler and Editor */
interface PocketAPI {}
class Pocket implements PocketAPI {}
interface JacketAPI {}
class Jacket implements JacketAPI {
public Jacket(PocketAPI labelStore) {}
}
public class Main {
public static void main(String[] args) {
System.out.println("!!!");
PocketAPI pocket = new Pocket();
JacketAPI jacket = new Jacket(pocket);
}
}
在Java中,所有对象都经过引用计数并存在于堆中。因此很容易获得它们的接口引用。
在 Rust 中,默认情况下值存在于堆栈中,并且不能转换为特征对象,因为特征对象的大小未知。它们不携带底层对象有多大的信息。
这意味着您需要创建对特征对象的大小引用;这可以通过两种方式完成:引用或作为堆对象 (
Box
)。
为了接近 Java 代码,我会使用
Box
:
pub trait XAPI {
fn new(y: Box<dyn YAPI>) -> Self;
}
pub trait YAPI {
fn new() -> Self;
}
pub struct X {}
pub struct Y {}
impl YAPI for Y {
fn new() -> Self {
Y {}
}
}
impl XAPI for X {
fn new(y: Box<dyn YAPI>) -> Self {
X {}
}
}
然而,这给我们带来了一个新问题;现在它说 '
YAPI
无法制作成对象'。这是真的,因为 YAPI
有一个静态函数(不包含 self
),这消除了它的 对象安全性。
原因有些复杂;简而言之,Rust 只能确定特征引用后面确实有一个对象,才能确定哪个对象位于该特征引用后面。然后它使用
self
引用来决定它是哪个对象(v 表和其他东西)。但是,如果您在对 YAPI 的特征引用上调用 new
,编译器将不知道要调用哪个函数,因为没有 self
连接到该调用。
因此,如果您从
new()
中删除 YAPI
,它将按预期工作:
pub trait XAPI {
fn new(y: Box<dyn YAPI>) -> Self;
}
pub trait YAPI {}
pub struct X {}
pub struct Y {}
impl Y {
fn new() -> Self {
Y {}
}
}
impl YAPI for Y {}
impl XAPI for X {
fn new(y: Box<dyn YAPI>) -> Self {
X {}
}
}
fn main() {
let y = Box::new(Y::new());
let x = X::new(y);
}