2017-06-22 19 views
7

Câu hỏi này tương tự như When is it useful to define multiple lifetimes in a struct?, nhưng hy vọng đủ khác biệt. Câu trả lời cho câu hỏi đó là hữu ích nhưng tập trung vào những ưu điểm của một cách tiếp cận (sử dụng thời gian sống riêng biệt cho các tham chiếu trong cấu trúc) nhưng không tập trung vào các hạn chế (nếu có). Câu hỏi này, như vậy, đang tìm kiếm hướng dẫn về cách chọn thời gian sống khi tạo cấu trúc.Tại sao bạn sẽ sử dụng cùng một thời gian để tham chiếu trong cấu trúc?

Gọi này ràng buộc với nhau phiên bản vì xy được yêu cầu phải có tuổi thọ tương tự:

struct Foo<'a> { 
    x: &'a i32, 
    y: &'a i32, 
} 

và gọi đây là lỏng phiên bản vì kiếp sống có thể khác nhau:

struct Foo<'a, 'b> { 
    x: &'a i32, 
    y: &'b i32, 
} 

Câu trả lời cho câu hỏi được tham chiếu đưa ra một trường hợp rõ ràng mã máy khách có thể biên dịch/chạy được cho phiên bản lỏng lẻo nhưng sẽ không thành công cho được gắn với nhau phiên bản. Không phải là trường hợp bất kỳ mã khách hàng nào hoạt động cho được gắn với nhau cũng sẽ hoạt động cho phiên bản lỏng lẻo và sẽ được đảm bảo cũng như an toàn (tức là an toàn)? Điều ngược lại không đúng. Phiên bản lỏng lẻo rõ ràng là linh hoạt hơn từ phối cảnh thiết kế struct. Cho nó là một câu trả lời tốt/chấp nhận hướng dẫn có thể là - khi sử dụng tài liệu tham khảo trong một cấu trúc luôn luôn cung cấp cho họ thời gian sống riêng biệt.

Nhược điểm của lời khuyên này là gì, bỏ qua việc nhập thêm? Ví dụ, có bao giờ có lợi cho yêu cầu tài liệu tham khảo trong cấu trúc có cùng thời gian không?

Trả lời

5

được có bao giờ được hưởng lợi để yêu cầu tài liệu tham khảo trong một cấu trúc có tuổi thọ cùng

Vâng, và nó vượt xa có một cấu trúc. Nếu kiếp luôn khác biệt với nhau, sau đó bạn không thể viết hàm này:

fn foo<'a, 'b>(a: &'a str, b: &'b str) -> &str { // What lifetime to return? 
    if (global_random_number() == 42) { a } else { b } 
} 

Áp dụng cho các cấu trúc, bạn có thể có một cái gì đó như thế này:

struct EvenOrOdd<'a, 'b> { 
    even: &'a str, 
    odd: &'b str, 
} 

impl<'a, 'b> EvenOrOdd<'a, 'b> { 
    fn do_it(&self, i: u8) -> &str { 
     if i % 2 == 0 { 
      self.even 
     } else { 
      self.odd 
     } 
    } 
} 

Lưu ý rằng trong khi điều này biên dịch, nó không trả về một chuỗi có thể sống lâu hơn cấu trúc của nó, mà không phải là những gì đã được dự định.Mã này thất bại, mặc dù nó có thể làm việc:

fn foo<'a, 'b>(a: &'a str, b: &'b str) { 
    let result = { 
     EvenOrOdd { even: a, odd: b }.do_it(42) 
    }; 

    println!("{}", result); 
} 

này sẽ làm việc với kiếp sống thống nhất:

struct EvenOrOdd<'a> { 
    even: &'a str, 
    odd: &'a str, 
} 

impl<'a> EvenOrOdd<'a> { 
    fn do_it(&self, i: u8) -> &'a str { 
     if i % 2 == 0 { self.even } else { self.odd } 
    } 
} 

Đây là trái ngược với câu trả lời liên quan, trong đó có những nhận xét:

bạn muốn có thể lấy giá trị tổng hợp và chia nhỏ các phần của nó sau khi sử dụng nó

Trong trường hợp này, chúng tôi muốn lấy giá trị tổng hợp và hợp nhất chúng.

Trong dịp hiếm, bạn có thể cần phải xâu kim giữa kiếp sống khác biệt và thống nhất:

struct EvenOrOdd<'a, 'b: 'a> { 
    even: &'a str, 
    odd: &'b str, 
} 

impl<'a, 'b> EvenOrOdd<'a, 'b> { 
    fn do_it(&self, i: u8) -> &'a str { 
     if i % 2 == 0 { self.even } else { self.odd } 
    } 
} 

Trong khi điều này rất hữu ích khi cần thiết, tôi không thể tưởng tượng khóc lóc và nghiến răng đó sẽ bùng phát nếu chúng tôi phải viết nó theo cách này mọi lúc.


bỏ qua thêm gõ

tôi sẽ không. Có

foo<'a>(Bar<'a>) 

chắc chắn là tốt hơn so với

foo<'a, 'b', 'c, 'd>(Bar<'a, 'b', 'c, 'd>) 

Khi bạn không được hưởng lợi từ các thông số chung thêm.

+0

Có thể * foo <...> (... b: & str) * phải là * foo <...> (... b: 'b & str) *? Không có lỗi biên dịch hoặc cảnh báo về phạm vi không sử dụng 'b. Với câu hỏi ban đầu, tôi nghĩ rằng cần cho các kiếp sống khác nhau là rất khó. Nhưng hey nếu nó có thể xảy ra chỉ làm cho họ độc lập. Tôi nghĩ rằng ví dụ này cho thấy lợi thế của cuộc đời giống nhau cũng rất contrived. Ai biết trước (hoặc nên biết) tất cả các vấn đề tiềm năng suốt đời của khách hàng có thể phải đối mặt? Để thêm hướng dẫn được nhập, tôi quay lại để chỉ đặt chúng giống nhau. Thật không may, một khi sự lựa chọn được thực hiện thay đổi không phải là dễ dàng. – user1338952

+0

@ user1338952 có, đại đa số các ví dụ được giả tạo; đó là cách các ví dụ hoạt động. Điểm thứ hai của bạn được gọi là * thiết kế phần mềm *. Ví dụ, tại sao bạn sẽ viết 'add (a: u8, b: u8)' khi bạn có thể viết 'thêm (a: A, b: A)' hoặc khi bạn có thể viết 'thêm (a: A, b: B) 'hoặc khi bạn có thể viết' thêm (a: A, b: B) '? Suy nghĩ về cách mã của bạn sẽ được sử dụng là điều làm cho phần mềm cả thách thức và bổ ích. Có, đôi khi chúng tôi nhận được sai, đôi khi chúng tôi phải thực hiện (phá vỡ) thay đổi. – Shepmaster

+0

Mọi blog bao gồm chủ đề (tức là * thiết kế phần mềm * lựa chọn khi chọn thời gian sống cho cấu trúc của bạn)? Đây là một chút hơn: đây là cách nó hoạt động. Sách phát hành * Lập trình Rust * có phần * Các thông số về thời gian sống riêng biệt * liên quan đến vấn đề. Dường như gợi ý là thử đầu tiên, nếu bạn thấy bạn cần chúng thay đổi chúng một cách độc lập. Không chắc chắn rằng quy mô. – user1338952

Các vấn đề liên quan