ในฐานะผู้ใช้ใหม่สู่สนิมความเข้าใจของฉันคืออายุการใช้งานที่ชัดเจนมีจุดประสงค์สองประการ
การใส่คำอธิบายประกอบตลอดชีวิตอย่างชัดเจนในฟังก์ชั่น จำกัด ประเภทของรหัสที่อาจปรากฏขึ้นภายในฟังก์ชั่นนั้น อายุขัยที่ชัดเจนช่วยให้คอมไพเลอร์มั่นใจว่าโปรแกรมของคุณกำลังทำสิ่งที่คุณตั้งใจไว้
หากคุณ (คอมไพเลอร์) ต้องการตรวจสอบว่าส่วนของโค้ดถูกต้องหรือไม่คุณ (คอมไพเลอร์) จะไม่ต้องดูในฟังก์ชั่นที่เรียกว่าซ้ำ ๆ มันพอเพียงที่จะดูคำอธิบายประกอบของฟังก์ชั่นที่ถูกเรียกโดยตรงโดยชิ้นส่วนของรหัสนั้น สิ่งนี้ทำให้โปรแกรมของคุณง่ายขึ้นที่จะให้เหตุผล (คอมไพเลอร์) ของคุณและทำให้เวลาในการคอมไพล์จัดการได้
บนจุดที่ 1 พิจารณาโปรแกรมต่อไปนี้เขียนใน Python:
import pandas as pd
import numpy as np
def second_row(ar):
return ar[0]
def work(second):
df = pd.DataFrame(data=second)
df.loc[0, 0] = 1
def main():
# .. load data ..
ar = np.array([[0, 0], [0, 0]])
# .. do some work on second row ..
second = second_row(ar)
work(second)
# .. much later ..
print(repr(ar))
if __name__=="__main__":
main()
ซึ่งจะพิมพ์
array([[1, 0],
[0, 0]])
พฤติกรรมแบบนี้ทำให้ฉันประหลาดใจเสมอ สิ่งที่เกิดขึ้นคือการที่df
หน่วยความจำที่ใช้ร่วมกันกับar
ดังนั้นเมื่อบางส่วนของเนื้อหาของdf
การเปลี่ยนแปลงในwork
ที่เปลี่ยนแปลงติดเชื้อar
เช่นกัน อย่างไรก็ตามในบางกรณีนี่อาจเป็นสิ่งที่คุณต้องการด้วยเหตุผลประสิทธิภาพหน่วยความจำ (ไม่มีการคัดลอก) ปัญหาที่แท้จริงในรหัสนี้คือฟังก์ชั่นsecond_row
จะกลับแถวแรกแทนที่สอง; ขอให้โชคดีที่แก้จุดบกพร่อง
พิจารณาโปรแกรมที่คล้ายกันที่เขียนใน Rust แทน
#[derive(Debug)]
struct Array<'a, 'b>(&'a mut [i32], &'b mut [i32]);
impl<'a, 'b> Array<'a, 'b> {
fn second_row(&mut self) -> &mut &'b mut [i32] {
&mut self.0
}
}
fn work(second: &mut [i32]) {
second[0] = 1;
}
fn main() {
// .. load data ..
let ar1 = &mut [0, 0][..];
let ar2 = &mut [0, 0][..];
let mut ar = Array(ar1, ar2);
// .. do some work on second row ..
{
let second = ar.second_row();
work(second);
}
// .. much later ..
println!("{:?}", ar);
}
รวบรวมสิ่งนี้คุณจะได้รับ
error[E0308]: mismatched types
--> src/main.rs:6:13
|
6 | &mut self.0
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `&mut &'b mut [i32]`
found type `&mut &'a mut [i32]`
note: the lifetime 'b as defined on the impl at 4:5...
--> src/main.rs:4:5
|
4 | impl<'a, 'b> Array<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 4:5
--> src/main.rs:4:5
|
4 | impl<'a, 'b> Array<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
ในความเป็นจริงคุณจะได้รับสองข้อผิดพลาดนอกจากนี้ยังเป็นหนึ่งเดียวกับบทบาทของ'a
และ'b
สบตา เมื่อดูที่คำอธิบายประกอบของsecond_row
เราพบว่าผลลัพธ์ควรเป็น&mut &'b mut [i32]
เช่นผลลัพธ์ที่ควรจะอ้างอิงถึงการอ้างอิงกับอายุการใช้งาน'b
(อายุการใช้งานของแถวที่สองของArray
) อย่างไรก็ตามเนื่องจากเรากำลังส่งคืนแถวแรก (ซึ่งมีอายุการใช้งานยาวนาน'a
) คอมไพเลอร์จึงบ่นเกี่ยวกับอายุการใช้งานที่ไม่ตรงกัน ในสถานที่ที่เหมาะสม ในเวลาที่เหมาะสม. การแก้ไขข้อบกพร่องเป็นเรื่องง่าย