以下代码无法编译:
ul li span {
display:block;
padding: 13.5px 0;
position: relative;
}
ul li span::after {
display: block;
content: "";
background: black;
height: 3px;
width: 0px;
transition: width 0.2s ease;
position: absolute;
bottom: 0;
left: 0;
}
ul li:nth-child(n+1)::before {
top: 20px;
}
ul li:hover span::after {
width: 100%;
}
我收到以下错误:
trait Phone {
fn call(&self);
}
struct IPhone<'a> {
my_str: &'a str
}
impl<'a> Phone for IPhone<'a> {
fn call(&self) {
print!("{}", self.my_str);
}
}
trait Factory<'a, P: Phone> {
fn new_phone(&self, ms: &'a str) -> P;
}
struct IPhoneFactory;
impl<'a> Factory<'a, IPhone<'a>> for IPhoneFactory {
fn new_phone(&self, ms: &'a str) -> IPhone<'a> {
return IPhone {
my_str: ms
};
}
}
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) {
for _ in 0..10 {
let s = String::new();
let p = f.new_phone(s.as_str());
p.call();
}
}
fn main() {
call_phone(IPhoneFactory);
}
我希望能够拥有一个返回抽象类的工厂,但是当该类接受引用时,我无法弄清楚如何正确指定生命周期。
答案 0 :(得分:4)
你是对的:
只要工厂生产,就没有理由生存,只需要工厂生产的对象就可以生存(工厂本身不存储对字符串的引用)。< / p>
但call_phone
上的界限表示不同的
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) { ... }
该代码表示整个工厂有单一生命周期,将用于每部手机。你想要一些不同的东西,你想说f
是任何生命周期的好工厂:
fn call_phone<..., F: for<'a> Factory<'a, ...>>(f: F) { ... }
另一个问题是Factory
特质定义:
trait Factory<'a, P: Phone> {
fn new_phone(&self, ms: &'a str) -> P;
}
P
到ms
的生命周期没有任何关系。特征定义允许返回的手机比字符串更长,绝对不能禁止IPhone
实施!因此,为了解决这个问题,我们将一个生命周期参数添加到Phone
特征:
trait Phone<'a> {
fn call(&self);
}
但还有一个问题。我们无法真正写下这个签名:
fn call_phone<P: ???, F: for<'a> Factory<'a, P<'a>>(f: F) { ... }
因为我们希望P
不是一个类型,而是一个类型族(更准确地说,是一个lifetime → type
构造函数)。请记住,循环的每次迭代中的电话具有不同的类型(因为生命周期是类型的一部分,并且循环的不同迭代中的生命期是不同的。)
为未来的Rust计划表达此类签名的能力,但是现在,我们必须制定解决方法并使手机关联类型为Factory
特征:
trait Phone<'a> {
fn call(&self);
}
struct IPhone<'a> {
my_str: &'a str
}
impl<'a> Phone<'a> for IPhone<'a> {
fn call(&self) {
println!("{}", self.my_str);
}
}
trait Factory<'a> {
type Output: Phone<'a>;
fn new_phone(&self, ms: &'a str) -> Self::Output;
}
struct IPhoneFactory;
impl<'a> Factory<'a> for IPhoneFactory {
type Output = IPhone<'a>;
fn new_phone(&self, ms: &'a str) -> IPhone<'a> {
IPhone {
my_str: ms
}
}
}
fn call_phone<F: for<'a> Factory<'a>>(f: F) {
for i in 0..10 {
let s = i.to_string();
let p = f.new_phone(&s);
p.call();
}
}
fn main() {
call_phone(IPhoneFactory);
}
关联类型允许工厂只生产一种产品,这可能是您想要的。如果您希望Factory
的不同实现具有不同的Output
,则可以通过使用幻像类型来实现此目的:
trait Phone<'a> {
type Phantom;
fn call(&self);
}
enum IPhonePhantom {}
struct IPhone<'a> {
my_str: &'a str
}
impl<'a> Phone<'a> for IPhone<'a> {
type Phantom = IPhonePhantom;
fn call(&self) {
println!("{}", self.my_str);
}
}
trait Factory<'a, Selector> {
type Output: Phone<'a, Phantom=Selector>;
fn new_phone(&self, ms: &'a str) -> Self::Output;
}
struct MyFactory;
impl<'a> Factory<'a, IPhonePhantom> for MyFactory {
type Output = IPhone<'a>;
fn new_phone(&self, ms: &'a str) -> IPhone<'a> {
IPhone {
my_str: ms
}
}
}
fn call_phone<Selector, F: for<'a> Factory<'a, Selector>>(f: F) {
for i in 0..10 {
let s = i.to_string();
let p = f.new_phone(&s);
p.call();
}
}
fn main() {
call_phone::<IPhonePhantom, _>(MyFactory);
}
Phantom
特征上的Phone
关联类型并非绝对必要,只需要将手机类型与其幻像类型联系起来,并确保Factory
个实施者不要说谎。
答案 1 :(得分:0)
你的问题在这里:
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) {
// Factory has a lifetime 'a ----------^
// that is at least as long as the scope of call_phone
for _ in 0..10 {
let s = String::new(); // s is born here
let p = f.new_phone(s.as_str());
// new reference ---^
// new_phone definition requires this to have
// the same lifetime 'a as the Factory
p.call();
}
// s is destroyed here, no references to s can
// still exist
} // F is still alive
您可以做的一件事是将&str
作为参数传递给call_phone
,以确保参考与函数一样长寿:
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F, s: &'a str) {
for _ in 0..10 {
let p = f.new_phone(s);
p.call();
}
}
fn main() {
call_phone(IPhoneFactory, &"hello");
}
另一个人不使用推荐,但让struct IPhone
拥有String