แยกการประกาศออกจากคำจำกัดความ

ฉันต้องการใช้ D จริงๆ เพราะโครงสร้างภาษาของมันทำดังนั้นหลายสิ่งที่ฉันสนใจดีกว่า C++ แต่เป็น GC ที่เกือบจะบังคับ (ปัญหาได้รับการจัดการ [ประเภท] ที่นี่) โอเปอเรเตอร์ที่มีประสิทธิภาพน้อยกว่าเล็กน้อย (ยกเว้น opDispatch opDispatch เซ็กซี่) และปัญหาต่อไปนี้ทำให้ฉันปิดใช้งาน

เป็นไปได้ไหมใน D ที่จะแยกการประกาศวิธีการออกจากคำจำกัดความ? ถ้าเป็นเช่นนั้นอย่างไร? ถ้าไม่ทำไม?

ตัวอย่างที่สร้างแรงบันดาลใจสำหรับ 'วิธีการ': เพื่อจัดเตรียมไฟล์ส่วนหัวขนาดเล็กของฟังก์ชันอินเทอร์เฟซถัดจากวัตถุไบนารี เช่นเดียวกับส่วนหัว C และไลบรารี เพื่อประโยชน์ในการซ่อนการใช้งานให้ห่างจากสายตาของผู้เขียนโค้ดผู้ใช้ การตั้งค่า: โดยไม่ต้องขึ้นอยู่กับว่าโค้ดผู้ใช้ได้แฮ็กตัวรวบรวมขยะไปแล้วหรือไม่ หรือเพียงแค่คอมไพล์โดยไม่ต้องรันไทม์ (เช่นนี้ที่พบในความคิดเห็นที่นี่)


d
person user    schedule 05.08.2013    source แหล่งที่มา
comment
อ่านเกี่ยวกับไฟล์อินเทอร์เฟซ D   -  person DejanLekic    schedule 06.08.2013
comment
@DejanLekic ฉันเห็นเฉพาะไฟล์อินเทอร์เฟซ D ที่ระบุในส่วนเอกสารประกอบของคอมไพเลอร์ มันเป็นสิ่งที่คอมไพเลอร์โดยคอมไพเลอร์หรือภาษา? แก้ไข: Blargh อ่านเพิ่มเติมอีกเล็กน้อยเกี่ยวกับพวกเขา พวกเขาไม่ได้เป็นส่วนหนึ่งของภาษา มีวิธีแก้ไขที่ IS เป็นส่วนหนึ่งของภาษาหรือไม่   -  person user    schedule 06.08.2013
comment
ไฟล์อินเทอร์เฟซ D กำลังใช้ส่วนอื่นของภาษา D เดียวกัน (อันที่จริงแล้ว คอมไพเลอร์ dmd ไม่สนใจว่านามสกุลจะเป็น .d หรือ .di พวกมันทำงานในลักษณะเดียวกัน)   -  person Adam D. Ruppe    schedule 06.08.2013
comment
@ AdamD.Ruppe A'ight - แต่คุณสามารถอธิบายคำพูดต่อไปนี้ให้ชัดเจนได้ไหม (จาก dlang.org/ dmd-linux.html#interface_files): ไฟล์อินเทอร์เฟซ D มีความคล้ายคลึงกับไฟล์ส่วนหัว C++ แต่ไม่จำเป็นในลักษณะเดียวกับไฟล์ส่วนหัว C++ และไม่ได้เป็นส่วนหนึ่งของภาษา D เป็นคุณสมบัติของคอมไพเลอร์ และทำหน้าที่เป็นเพียงการปรับกระบวนการสร้างให้เหมาะสมที่สุดเท่านั้น   -  person user    schedule 06.08.2013
comment
@ AdamD.Ruppe ฉันหมายถึงเพื่อให้ชัดเจนฉันจะไม่เป็นคนเจ้าระเบียบและบอกว่าไฟล์ .di ที่ไม่ได้เป็นส่วนหนึ่งของคำจำกัดความภาษาหลักนั้นถูกปิด ฉันแค่อยากจะรู้ว่าเกิดอะไรขึ้นกับพวกเขา   -  person user    schedule 06.08.2013


คำตอบ (3)


ถ้าฉันเขียนไฟล์ D แบบนี้: http://arsdnet.net/dcode/iface/test.d และคุณคอมไพล์ด้วย dmd -c คุณจะเห็นว่ามันดำเนินไปโดยไม่มีข้อผิดพลาด นั่นเป็นไฟล์ D ที่ถูกต้อง ภาษานี้ช่วยให้คุณเขียนฟังก์ชันต้นแบบได้โดยไม่ต้องใช้งาน

ไฟล์ .di ก็เป็นแบบนั้น เพียงแต่มีชื่อไฟล์ที่แตกต่างกัน

จากนั้นกำหนด main: http://arsdnet.net/dcode/main.d หากคุณคอมไพล์ dmd main มันจะค้นหา iface/test.d โดยอัตโนมัติเมื่อเห็น "import iface.test;" ค้นหาไฟล์ .d หรือ .di หากคุณเปลี่ยนชื่อไฟล์เหมือนกัน และรับคำจำกัดความอินเทอร์เฟซของคุณ

dmd main จะล้มเหลวโดยมีข้อผิดพลาดของตัวเชื่อมโยง ดังนั้นเราจึงจำเป็นต้องดำเนินการ: http://arsdnet.net/dcode/impl.d หมายเหตุ: impl จะไม่นำเข้าโมดูล ดังนั้นจึงไม่เคยตรวจสอบไฟล์อื่นเลย การเก็บไฟล์ .di และ .d ให้ตรงกันเป็นส่วนที่ยุ่งยากอย่างหนึ่ง เว้นแต่คุณจะสร้างไฟล์อินเทอร์เฟซโดยอัตโนมัติ เนื่องจากวิธีการที่ไม่ได้กำหนดไว้อาจทำให้เกิดข้อผิดพลาดของตัวเชื่อมโยง แต่ลำดับของวิธีการมีความสำคัญ: ต้องตรงกัน และทำเช่นนั้น รายการตัวแปรหากมีตัวแปรสาธารณะอยู่ มิฉะนั้น รหัสการใช้งานและรหัสการใช้งานจะไม่สอดคล้องกับโครงร่างของชั้นเรียน

ขอย้ำอีกครั้งว่า ไม่ ตรวจสอบโดยอัตโนมัติ ไฟล์การใช้งานไม่ได้ดูไฟล์ "ส่วนหัว" เลย ดังนั้นนี่คือข้อแตกต่างที่สำคัญจาก C++ ที่คุณเขียนไฟล์ส่วนหัวหนึ่งครั้ง จากนั้นใช้ ทั้งในโปรแกรมการใช้งานและไฟล์การใช้งาน

คุณจะสังเกตเห็นว่าไฟล์การใช้งานยังแสดงรายการคลาส ฯลฯ ด้วยเช่นกัน D ไม่รองรับไวยากรณ์ void MyClass::add(int a) {} C++ ต้องเขียนเมธอดนอกคลาส

เท่าที่ฉันรู้ ไม่มีวิธีบังคับให้ไฟล์การใช้งานค้นหาส่วนหัว หากคุณใส่ทั้งสองอย่างบนบรรทัดคำสั่ง คุณจะได้รับ: "ข้อผิดพลาด: โมดูล iface.test จากไฟล์ iface/test.d ขัดแย้งกับโมดูลอื่น ทดสอบจากไฟล์ impl.d"

วิธีที่แนะนำให้ใช้ไฟล์ .di คือการสร้างไฟล์อัตโนมัติด้วย dmd -H การดำเนินการนี้จะอ่านไฟล์การใช้งานแบบเต็มและตัดส่วนเนื้อหาของฟังก์ชันออก เหลือเพียงคำจำกัดความ ส่วนนี้น่าจะเป็นสิ่งสำคัญเมื่อพวกเขาบอกว่ามันเป็นคุณสมบัติของคอมไพเลอร์ - ไฟล์ .di นั้นถูกต้องและเป็นมาตรฐาน D แต่สร้างขึ้นผ่านตัวเลือกคอมไพเลอร์ที่ไม่จำเป็นต้องเป็นส่วนหนึ่งของคอมไพเลอร์อื่น ๆ

person Adam D. Ruppe    schedule 06.08.2013
comment
dmd main เพื่อดูข้อผิดพลาดและ dmd main.d impl.d เพื่อดูว่าทำงานได้สำเร็จ ดาวน์โหลดทั้งสองไฟล์ไปยังโฟลเดอร์ของคุณเอง - person Adam D. Ruppe; 24.06.2015

คุณสามารถประกาศฟังก์ชันโดยไม่ต้องระบุการใช้งานได้โดยใช้ extern เช่น:

extern(D):
void foo(string name);

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

person Justin W    schedule 05.08.2013
comment
ไฟล์ FWIW, .di เป็นเพียงระบบอัตโนมัติของแบบแผนนั้น - person BCS; 06.08.2013
comment
@BCS และด้วยเหตุนี้มันจึงกลายเป็นคำแนะนำสำหรับฉันอยู่ดี ขอบคุณทุกท่าน. - person user; 07.08.2013

อดัมอธิบายทุกอย่างแล้ว ฉันจะพยายามเพิ่มตัวอย่างเพิ่มเติม:

สมมติว่าคุณกำลังพัฒนาไลบรารีชื่อ mylib และมีฟังก์ชัน foo() และ bar() แอปพลิเคชันทดสอบโค้ดและไลบรารีของคุณอาจมีลักษณะเช่นนี้เมื่อเริ่มต้น:

mylib.d - ไฟล์อินเทอร์เฟซ

module mylib;

void foo();
void bar();

mylib_impl.d - คำจำกัดความอยู่ที่นี่

module mylib;

import std.stdio;

void foo() {
  writeln("foo()");
}

void bar() {
  writeln("bar()");
}

mylib_test.d - แอปพลิเคชันทดสอบ

// To compile: dmd mylib_impl.d mylib_test.d
// NOTE: we do not compile the "interface" file mylib.d !!
module mylib_test;

import mylib;

int main() {
  foo();
  bar();

  return 0;
}

ตอนนี้ไม่ใช่เรื่องยากที่จะเข้าใจว่าเรามีไฟล์ .di เพื่อความสะดวกและชัดเจนเท่านั้น หากเราตัดสินใจใช้ไฟล์อินเทอร์เฟซ เราจะเปลี่ยนชื่อ mylib.d เป็น mylib.di และ mylib_impl.d เป็น mylib.d mylib_test.d จะยังคงเหมือนเดิม

person DejanLekic    schedule 06.08.2013
comment
แพ็คเกจเป็นเพียงไดเร็กทอรี มันควรจะทำงานโดยไม่มีการเปลี่ยนแปลง - person DejanLekic; 24.06.2015