ฉันจะเชื่อมสตริงเข้าด้วยกันได้อย่างไร


201

ฉันจะต่อชุดประเภทต่อไปนี้เข้าด้วยกันได้อย่างไร:

  • str และ str
  • String และ str
  • String และ String

14
โปรดทราบว่าstrและ&strเป็นชนิดที่แตกต่างกันและสำหรับ 99% &strของเวลาที่คุณควรดูแลเกี่ยวกับ มีคำถามอื่น ๆ ที่แสดงรายละเอียดความแตกต่างระหว่างพวกเขา
Shepmaster

คำตอบ:


235

เมื่อคุณต่อสตริงคุณต้องจัดสรรหน่วยความจำเพื่อจัดเก็บผลลัพธ์ วิธีที่ง่ายที่สุดในการเริ่มต้นคือStringและ&str:

fn main() {
    let mut owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";

    owned_string.push_str(borrowed_string);
    println!("{}", owned_string);
}

ที่นี่เรามีสตริงที่เป็นเจ้าของที่เราสามารถกลายพันธุ์ได้ สิ่งนี้มีประสิทธิภาพเพราะอาจช่วยให้เราสามารถนำการจัดสรรหน่วยความจำกลับมาใช้ใหม่ มีกรณีคล้ายกันสำหรับการเป็นStringและStringเป็น&String สามารถ dereferenced &strเป็น

fn main() {
    let mut owned_string: String = "hello ".to_owned();
    let another_owned_string: String = "world".to_owned();

    owned_string.push_str(&another_owned_string);
    println!("{}", owned_string);
}

หลังจากนี้another_owned_stringจะไม่มีการแตะต้อง (หมายเหตุไม่มีตัวระบุmut) มีอีกรุ่นหนึ่งที่ใช้งานStringแต่ไม่ต้องการให้เปลี่ยนแปลงได้ นี่คือการดำเนินการตามAddลักษณะที่Stringเป็นด้านซ้ายและด้าน&strขวา:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";

    let new_owned_string = owned_string + borrowed_string;
    println!("{}", new_owned_string);
}

โปรดทราบว่าไม่สามารถเข้าถึงได้หลังจากการเรียกร้องให้owned_string+

เกิดอะไรขึ้นถ้าเราต้องการที่จะผลิตสตริงใหม่ปล่อยให้ทั้งสองไม่มีใครแตะต้อง? วิธีที่ง่ายที่สุดคือการใช้format!:

fn main() {
    let borrowed_string: &str = "hello ";
    let another_borrowed_string: &str = "world";

    let together = format!("{}{}", borrowed_string, another_borrowed_string);
    println!("{}", together);
}

โปรดทราบว่าตัวแปรอินพุตทั้งสองนั้นไม่เปลี่ยนรูปดังนั้นเราจึงรู้ว่าไม่ได้ถูกแตะต้อง หากเราต้องการทำสิ่งเดียวกันสำหรับชุดค่าผสมใด ๆStringเราสามารถใช้ความจริงที่ว่าStringสามารถจัดรูปแบบได้:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let another_owned_string: String = "world".to_owned();

    let together = format!("{}{}", owned_string, another_owned_string);
    println!("{}", together);
}

คุณไม่ได้ใช้format!แต่ คุณสามารถโคลนหนึ่งสตริงและผนวกสตริงอื่น ๆ กับสตริงใหม่:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";

    let together = owned_string.clone() + borrowed_string;
    println!("{}", together);
}

หมายเหตุ - ข้อมูลจำเพาะประเภททั้งหมดที่ฉันทำซ้ำซ้อน - คอมไพเลอร์สามารถอนุมานทุกประเภทในการเล่นที่นี่ ฉันเพิ่มพวกเขาเพื่อให้ชัดเจนกับผู้ที่เพิ่งรู้จักกับ Rust เนื่องจากฉันคาดหวังว่าคำถามนี้จะเป็นที่นิยมในกลุ่มนั้น


2
คุณคิดอย่างไรเกี่ยวกับAdd/ +สัญลักษณ์? คุณสามารถครอบคลุมได้ถ้าคุณต้องการ
bluss

อาจจะง่ายพอ แต่การทำความเข้าใจมันต้องดูที่ลายเซ็นประเภทที่เป็นไปได้สำหรับ Add with String
bluss

ขอบคุณ! คุณสามารถที่จะเจาะลึกลงไปอีกเล็กน้อยว่า & สตริงสามารถถูกอ้างถึงเป็น & str ได้หรือไม่? ส่วนใดของการนำไปใช้งานอนุญาตให้ทำเช่นนั้นและ / หรือที่ไหนที่จะกล่าวสิ่งนี้ใน doco
jsalter

1
@jsalter เป็นหัวข้อที่ค่อนข้างจะแยกกันดังนั้นมันอาจจะดีเหมือนคำถามระดับสูงอื่น ฉันได้อัปเดตเพื่อเชื่อมโยงไปยังเอกสารที่เหมาะสม (อย่างน้อยที่สุดฉันจะได้ ... )
Shepmaster

10
@ChrisMorgan มันควรจะสังเกตว่าความแตกต่าง.to_owned()และ.to_string()ได้รับการแก้ไขตั้งแต่ความคิดเห็นข้างต้นต้องขอบคุณความเชี่ยวชาญ &strพวกเขาทั้งสองในขณะนี้มีประสิทธิภาพการทำงานที่เดียวกันเมื่อเรียกบน การกระทำที่เกี่ยวข้อง: github.com/rust-lang/rust/pull/32586/files
chad

49

ในการต่อหลายสตริงให้เป็นสตริงเดียวโดยคั่นด้วยอักขระอื่นมีสองวิธี

สิ่งที่ดีที่สุดที่ฉันเคยเห็นคือการใช้joinวิธีการในอาร์เรย์:

fn main() {
    let a = "Hello";
    let b = "world";
    let result = [a, b].join("\n");

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

ขึ้นอยู่กับกรณีการใช้งานของคุณคุณอาจต้องการการควบคุมมากกว่านี้:

fn main() {
    let a = "Hello";
    let b = "world";
    let result = format!("{}\n{}", a, b);

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

มีวิธีการด้วยตนเองเพิ่มเติมที่ฉันได้เห็นบางคนหลีกเลี่ยงการจัดสรรหนึ่งหรือสองที่นี่และที่นั่น เพื่อวัตถุประสงค์ในการอ่านฉันพบว่าทั้งสองข้างต้นมีเพียงพอ


joinเอกสารอยู่ที่ไหน ดูเหมือนว่าจะนั่งครึ่งทางระหว่าง Array และ String ฉันค้นหาเอกสารประกอบอาร์เรย์และสับสนอย่างรวดเร็ว
ดวน J

3
@DuaneJ joinแนบมาจริงลักษณะ ลักษณะถูกทำเครื่องหมายไม่เสถียร แต่วิธีการของมันมีความเสถียรและรวมอยู่ในโหมโรงเพื่อให้พวกเขาสามารถใช้งานได้ทุกที่โดยค่าเริ่มต้น ทีมดูเหมือนจะตระหนักดีถึงคุณลักษณะนี้ไม่จำเป็นต้องมีอยู่และฉันคิดว่าสิ่งต่าง ๆ จะเปลี่ยนแปลงในอนาคตด้วย SliceContactExt
Simon Whitehead

9

ฉันคิดว่าconcatวิธีการและ+ควรได้รับการกล่าวถึงที่นี่เช่นกัน:

assert_eq!(
  ("My".to_owned() + " " + "string"),
  ["My", " ", "string"].concat()
);

และยังมีconcat!มาโคร แต่เฉพาะสำหรับตัวอักษร:

let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");

+เป็นที่กล่าวถึงแล้วในคำตอบที่มีอยู่ ( นี่คือการดำเนินการของAddลักษณะที่ใช้Stringเป็นด้านซ้ายและ&strเป็นด้านขวามือ )
Shepmaster

จริงคำตอบที่มีอยู่กว้างมากฉันไม่ได้สังเกตว่า
suside

6

วิธีง่ายๆในการต่อสตริงใน RUST

มีวิธีการต่างๆใน RUST เพื่อต่อสตริงเข้าด้วยกัน

วิธีแรก (โดยใช้concat!()):

fn main() {
    println!("{}", concat!("a", "b"))
}

ผลลัพธ์ของรหัสข้างต้นคือ:

AB


วิธีที่สอง (การใช้push_str()และ+โอเปอเรเตอร์):

fn main() {
    let mut _a = "a".to_string();
    let _b = "b".to_string();
    let _c = "c".to_string();

    _a.push_str(&_b);
    
    println!("{}", _a);
 
    println!("{}", _a + &_b);
}

ผลลัพธ์ของรหัสข้างต้นคือ:

AB

abc


วิธีที่สาม ( Using format!()):

fn main() {
    let mut _a = "a".to_string();
    let _b = "b".to_string();
    let _c = format!("{}{}", _a, _b);
    
    println!("{}", _c);
}

ผลลัพธ์ของรหัสข้างต้นคือ:

AB

ลองดูและทดลองเล่นกับRust play ground


คำตอบนี้ไม่ได้เพิ่มอะไรใหม่ในคำตอบที่มีอยู่
Shepmaster
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.