ไวยากรณ์สำหรับลิเทอรัลสตริงหลายบรรทัดคืออะไร


136

ฉันมีปัญหาในการหาวิธีการทำงานของไวยากรณ์สตริงใน Rust โดยเฉพาะฉันกำลังพยายามหาวิธีสร้างสตริงหลายบรรทัด


คำตอบ:


173

ตัวอักษรสตริงทั้งหมดสามารถแบ่งได้หลายบรรทัด ตัวอย่างเช่น:

let string = "line one
line two";

เป็นสตริงสองบรรทัดเหมือนกับ"line one\nline two"(แน่นอนว่าหนึ่งสามารถใช้การขึ้น\nบรรทัดใหม่ได้โดยตรงเช่นกัน) หากคุณต้องการทำลายสตริงในหลาย ๆ บรรทัดด้วยเหตุผลในการจัดรูปแบบคุณสามารถหลีกเลี่ยงการขึ้นบรรทัดใหม่และช่องว่างนำหน้าด้วย a \; ตัวอย่างเช่น:

let string = "one line \
    written over \
    several";

เหมือนกับ"one line written over several".

หากคุณต้องการให้เส้นแบ่งในสตริงคุณสามารถเพิ่มได้ก่อน\:

let string = "multiple\n\
              lines\n\
              with\n\
              indentation";

มันเหมือนกับ "multiple\nlines\nwith\nindentation";


2
หากมีปัญหาในการอ่านเท่านั้นฉันต้องการเพิ่มconcat!()มาโครเพื่อเติมเต็มตัวเลือกที่กำหนด ( doc.rust-lang.org/std/macro.concat.html )
hakononakani

85

ในกรณีที่คุณต้องการทำอะไรให้ยาวขึ้นเล็กน้อยซึ่งอาจมีหรือไม่มีเครื่องหมายอัญประกาศแบ็กสแลช ฯลฯ ให้ใช้สัญกรณ์อักษรสตริงดิบ :

let shader = r#"
    #version 330

    in vec4 v_color;
    out vec4 color;

    void main() {
        color = v_color;
    };
"#;

หากคุณมีลำดับของเครื่องหมายคำพูดคู่และสัญลักษณ์แฮชภายในสตริงของคุณคุณสามารถระบุจำนวนแฮชโดยพลการเป็นตัวคั่นได้:

let crazy_raw_string = r###"
    My fingers #"
    can#"#t stop "#"" hitting
    hash##"#
"###;

แต่ ... คุณจะต้องหลีกเลี่ยงการขึ้นบรรทัดใหม่หากคุณไม่ต้องการขึ้นบรรทัดใหม่ในผลลัพธ์และสตริงดิบไม่ช่วยในเรื่องนั้น
poolie

สตริงดิบช่วยป้องกันไม่ให้คุณต้องเพิ่ม '\' ที่ท้ายทุกบรรทัดหากคุณไม่สนใจขึ้นบรรทัดใหม่ (เช่นเมื่อคุณกำลังฝังโค้ดซึ่งไม่เชื่อเรื่องพระเจ้าแบบใหม่เช่นเฉดสีและเมล็ด) หรือตามที่คุณกล่าวถึง ถึงเมื่อขึ้นบรรทัดใหม่เป็นสิ่งที่จำเป็นจริงๆ ทำให้การฝังโค้ดง่ายขึ้นซึ่งคุณอาจต้องการแก้ไขและไม่ต้องยุ่งยากกับ '\' ที่ท้ายแต่ละบรรทัด นั่นคือทั้งหมด
c0g

1
หากคุณต้องการ (หรือไม่สนใจ) ขึ้นบรรทัดใหม่ในสตริงผลลัพธ์สตริงที่ยกมาคู่ธรรมดาจะทำได้ดีอย่างสมบูรณ์ดังที่แสดงในตัวอย่างอื่น ๆ หากคุณต้องการหลีกเลี่ยงการขึ้นบรรทัดใหม่สตริงดิบก็ไม่ดี ซึ่งจะช่วยได้มากก็ต่อเมื่อข้อความมีเครื่องหมายอัญประกาศแบ็กสแลช ฯลฯ ซึ่งอาจเกิดขึ้นในแหล่งที่มาที่ฝังไว้
poolie

2
ฉันเห็นสิ่งที่คุณได้รับในตอนนี้และคุณพูดถูกจริงๆ
c0g

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

48

คำตอบของ Huonถูกต้อง แต่ถ้าการเยื้องรบกวนคุณให้พิจารณาใช้Indocซึ่งเป็นมาโครขั้นตอนสำหรับสตริงหลายบรรทัดที่เยื้อง ย่อมาจาก "เอกสารเยื้อง" มีมาโครที่เรียกindoc!()ว่าใช้สตริงแบบหลายบรรทัดและยกเลิกการเยื้องเพื่อให้อักขระที่ไม่ใช่ช่องว่างซ้ายสุดอยู่ในคอลัมน์แรก

let s = indoc! {"
    line one
    line two
"};

"line one\nline two\n"ผลที่ได้คือ

ช่องว่างจะถูกเก็บรักษาไว้โดยสัมพันธ์กับอักขระที่ไม่ใช่ช่องว่างด้านซ้ายสุดในเอกสารดังนั้นต่อไปนี้จึงมีช่องว่าง 3 ช่องที่เยื้อง 2 บรรทัดเทียบกับบรรทัดที่หนึ่ง:

let s = indoc! {"
    line one
       line two
"};

"line one\n line two\n"ผลที่ได้คือ


9

ในกรณีที่คุณต้องการเยื้องข้อความหลายบรรทัดในโค้ดของคุณ:

let s = "first line\n\
    second line\n\
    third line";

println!("Multiline text goes next:\n{}", s);

ผลลัพธ์จะเป็นดังนี้:

Multiline text goes next:
first line
second line
third line

โปรดระบุอย่างชัดเจนโดยใช้ร้อยแก้วว่าส่วนใดของรหัสที่สำคัญต่อพฤติกรรมนี้
Shepmaster

ตอนนี้ดูเหมือนว่าจะไม่เพิ่มอะไรใหม่ให้กับคำตอบที่ยอมรับซึ่งระบุว่า: เราสามารถใช้\nnewline escape [... ] คุณสามารถออกจากบรรทัดใหม่และช่องว่างนำหน้าด้วย a{backslash} . (มันยากมากที่จะพิมพ์แบ็กสแลชในโค้ดในความคิดเห็นมันจะปรากฏขึ้น)
Shepmaster

2
ความคิดเห็นนี้แนะนำวิธีการรวมสองจุดในคำตอบที่ยอมรับ: คุณสามารถสร้างสตริงหลายบรรทัดโดยเขียนเป็นบรรทัดหลายบรรทัดในโค้ดได้อย่างไร แต่ในเวลาเดียวกันจะได้รับอนุญาตให้ - ด้วยเหตุผลทางโวหารหรือความชัดเจน - รับ การเยื้องของตัวเองในรหัสโดยไม่มีการเยื้องนี้ลงท้ายด้วยสตริงสุดท้าย ข้อความไม่ชัดเจนมากนัก แต่เป็นกรณีการใช้งานทั่วไปดังนั้นจึงเป็นข้อเสนอแนะที่มีค่า imho (ดูคำตอบโดย dtolnay สำหรับรุ่นลังของสิ่งนี้)
Dato

0

หากคุณต้องการควบคุมช่องว่างในสตริงหลายเส้นแบบละเอียดโดยไม่ต้องใช้ลังภายนอกคุณสามารถทำการต่อไปนี้ได้ ตัวอย่างจากโครงการของฉันเอง

impl Display for OCPRecData {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "OCPRecData {{\n\
            \x20   msg: {:?}\n\
            \x20   device_name: {:?}\n\
            \x20   parent_device_name: {:?}\n\
        }}", self.msg, self.device_name, self.parent_device_name)
    }
}

ผลลัพธ์ใน

OCPRecData {
    msg: Some("Hello World")
    device_name: None
    parent_device_name: None
}
  • \n\ ที่ปลายบรรทัดรหัสแต่ละบรรทัดจะสร้างตัวแบ่งบรรทัดในตำแหน่งที่เหมาะสมและละทิ้งช่องว่างเพิ่มเติมในบรรทัดของโค้ดนี้
  • \x20 (hex; 32 ในฐานสิบ) คือช่องว่าง ASCII และตัวบ่งชี้สำหรับช่องว่างแรกที่จะรักษาไว้ในบรรทัดของสตริงนี้
  • \x20\x20\x20\x20และ\x20 มีผลเช่นเดียวกัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.