มีเหตุผลหรือไม่ที่การมอบหมายอาร์เรย์ Swift ไม่สอดคล้องกัน (ไม่มีการอ้างอิงหรือสำเนาที่ลึก)?


216

ฉันกำลังอ่านเอกสารและฉันส่ายหัวอย่างต่อเนื่องในการตัดสินใจออกแบบภาษา แต่สิ่งที่ทำให้ฉันงงจริงๆคือวิธีจัดการกับอาร์เรย์

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

var a = [1, 2, 3]
var b = a
a[1] = 42
a
b

ที่นี่aและbเป็นทั้งคู่[1, 42, 3]ซึ่งฉันสามารถยอมรับได้ มีการอ้างอิงอาร์เรย์ - ตกลง!

ตอนนี้ดูตัวอย่างนี้:

var c = [1, 2, 3]
var d = c
c.append(42)
c
d

cเป็น[1, 2, 3, 42]แต่เป็นd [1, 2, 3]นั่นคือdเห็นการเปลี่ยนแปลงในตัวอย่างสุดท้าย แต่ไม่เห็นในตัวอย่างนี้ เอกสารบอกว่าเป็นเพราะความยาวเปลี่ยนไป

ทีนี้ลองดูอันนี้:

var e = [1, 2, 3]
var f = e
e[0..2] = [4, 5]
e
f

eคืออะไร[4, 5, 3]ซึ่งเท่ห์ มันดีที่มีการแทนที่หลายดัชนี แต่fSTILL ไม่เห็นการเปลี่ยนแปลงแม้ว่าความยาวจะไม่เปลี่ยนแปลง

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

ดูเหมือนว่าการออกแบบที่แย่มากสำหรับฉัน ฉันคิดถูกไหม มีเหตุผลที่ฉันไม่เห็นหรือไม่ว่าทำไมอาร์เรย์จึงควรทำแบบนี้?

แก้ไข : อาร์เรย์มีการเปลี่ยนแปลงและตอนนี้มีความหมายของค่า มีสติมากขึ้น!


95
สำหรับบันทึกแล้วฉันไม่คิดว่าควรปิดคำถามนี้ Swift เป็นภาษาใหม่ดังนั้นจะมีคำถามเช่นนี้มาระยะหนึ่งในขณะที่เราทุกคนเรียนรู้ ฉันพบว่าคำถามนี้น่าสนใจมากและฉันหวังว่าจะมีคนสนใจคดีนี้
Joel Berger

4
@ Joel Fine ขอให้โปรแกรมเมอร์เขียนโปรแกรม Stack Overflow สำหรับปัญหาการเขียนโปรแกรมที่ไม่ได้กำหนดไว้โดยเฉพาะ
bjb568

21
@ bjb568: มันไม่ใช่ความเห็น คำถามนี้ควรตอบได้ด้วยข้อเท็จจริง หากนักพัฒนา Swift บางคนเข้ามาและตอบ "เราทำอย่างนั้นสำหรับ X, Y และ Z" นั่นเป็นข้อเท็จจริงที่ตรงไปตรงมา คุณอาจไม่เห็นด้วยกับ X, Y และ Z แต่ถ้ามีการตัดสินใจสำหรับ X, Y และ Z นั่นเป็นเพียงข้อเท็จจริงทางประวัติศาสตร์ของการออกแบบภาษา เหมือนเมื่อฉันถามว่าทำไมstd::shared_ptrไม่มีรุ่นที่ไม่ใช่อะตอมมีคำตอบตามความเป็นจริงไม่ใช่ความเห็น (ความจริงก็คือคณะกรรมการพิจารณาแล้ว แต่ไม่ต้องการเหตุผลหลายประการ)
Cornstalks

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

7
ใช่ดังที่ API-Beast กล่าวว่าโดยทั่วไปจะเรียกว่า "การออกแบบคัดลอกครึ่งภาษา - การออกแบบภาษา"
R. Martinho Fernandes

คำตอบ:


109

โปรดทราบว่าซีแมนทิกส์และไวยากรณ์ของอาร์เรย์มีการเปลี่ยนแปลงในเวอร์ชัน Xcode เบต้า 3 ( บล็อกโพสต์ ) ดังนั้นคำถามจะไม่ถูกนำไปใช้อีกต่อไป คำตอบต่อไปนี้นำไปใช้กับเบต้า 2:


สำหรับเหตุผลด้านประสิทธิภาพ โดยทั่วไปแล้วพวกเขาพยายามหลีกเลี่ยงการคัดลอกอาร์เรย์ตราบใดที่พวกเขาสามารถทำได้ (และเรียกร้อง "ประสิทธิภาพเหมือน C") วิธีอ้างอิงหนังสือภาษา:

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

ฉันยอมรับว่านี่เป็นความสับสนเล็กน้อย แต่อย่างน้อยก็มีคำอธิบายที่ชัดเจนและเรียบง่ายว่ามันทำงานอย่างไร

ส่วนนั้นยังมีข้อมูลเกี่ยวกับวิธีการตรวจสอบให้แน่ใจว่ามีการอ้างอิงอาเรย์ที่ไม่ซ้ำกันวิธีการบังคับให้คัดลอกอาร์เรย์และวิธีตรวจสอบว่ามีสองอาร์เรย์ที่เก็บข้อมูลร่วมกันหรือไม่


61
ฉันพบความจริงที่ว่าคุณมีทั้งการแบ่งปันและคัดลอกธงสีแดงขนาดใหญ่ในการออกแบบ
Cthutu

9
สิ่งนี้ถูกต้อง วิศวกรคนหนึ่งอธิบายให้ฉันฟังว่าสำหรับการออกแบบภาษานี้ไม่เป็นที่ต้องการและเป็นสิ่งที่พวกเขาหวังว่าจะ "แก้ไข" ในการอัปเดตของ Swift ที่กำลังจะมาถึง โหวตด้วยเรดาร์
Erik Kerber

2
มันเป็นอะไรที่เหมือนกับ copy-on-write (COW) ในการจัดการหน่วยความจำกระบวนการลูกลินุกซ์ใช่ไหม? บางทีเราสามารถเรียกมันว่า copy-on-length-alteration (COLA) ฉันเห็นสิ่งนี้เป็นการออกแบบเชิงบวก
justhalf

3
@ justhalf ฉันสามารถคาดการณ์ว่าจะมีมือใหม่ที่สับสนมาถึงและถามว่าทำไมอาร์เรย์ของพวกเขาจึงถูก / ไม่ถูกแชร์ (ในวิธีที่ชัดเจนน้อยกว่า)
John Dvorak

11
@justhalf: COW เป็นการมองโลกในแง่ร้ายต่อไปในอนาคตและประการที่สอง COW เป็นเทคนิคการดำเนินการอย่างเดียวและสิ่งที่ COLA นี้นำไปสู่การแบ่งปันและการแบ่งปันแบบสุ่มโดยสิ้นเชิง
ลูกสุนัข

25

จากเอกสารอย่างเป็นทางการของภาษา Swift :

โปรดทราบว่าอาร์เรย์จะไม่คัดลอกเมื่อคุณตั้งค่าใหม่ด้วยไวยากรณ์ห้อยเนื่องจากการตั้งค่าเดียวกับไวยากรณ์ห้อยไม่มีโอกาสที่จะเปลี่ยนความยาวของอาร์เรย์ แต่ถ้าคุณผนวกรายการใหม่ไปยังอาร์เรย์คุณจะปรับเปลี่ยนความยาวของอาเรย์ สิ่งนี้จะแจ้งให้ Swift สร้างสำเนาใหม่ของอาร์เรย์ณ จุดที่คุณผนวกค่าใหม่ ต่อจากนี้ไป a จะเป็นสำเนาที่เป็นอิสระจากอาร์เรย์ .....

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


4
ขอบคุณ ฉันอ้างถึงข้อความนั้นอย่างคลุมเครือในคำถามของฉัน แต่ฉันแสดงตัวอย่างที่การเปลี่ยนช่วงตัวห้อยไม่ได้เปลี่ยนความยาวและยังคงคัดลอก ดังนั้นหากคุณไม่ต้องการให้สำเนาคุณต้องเปลี่ยนองค์ประกอบทีละรายการ
Cthutu

21

พฤติกรรมเปลี่ยนไปด้วย Xcode 6 beta 3 อาร์เรย์เป็นประเภทอ้างอิงอีกต่อไปและมีกลไกการคัดลอกเมื่อเขียนหมายถึงทันทีที่คุณเปลี่ยนเนื้อหาของอาร์เรย์จากตัวแปรหนึ่งตัวหรือตัวแปรอื่นอาร์เรย์จะถูกคัดลอกและเฉพาะ หนึ่งสำเนาจะถูกเปลี่ยน


คำตอบเก่า:

ดังที่คนอื่น ๆ ได้ชี้ให้เห็น Swift พยายามหลีกเลี่ยงการคัดลอกอาร์เรย์ถ้าเป็นไปได้รวมถึงเมื่อเปลี่ยนค่าสำหรับดัชนีเดี่ยวในแต่ละครั้ง

หากคุณต้องการแน่ใจว่าตัวแปร array (!) ไม่ซ้ำกันนั่นคือไม่ได้ใช้ร่วมกับตัวแปรอื่นคุณสามารถเรียกใช้unshareเมธอดได้ สิ่งนี้จะคัดลอกอาร์เรย์เว้นแต่ว่ามันจะมีเพียงหนึ่งการอ้างอิง แน่นอนคุณยังสามารถเรียกcopyวิธีการซึ่งมักจะทำสำเนา แต่ยกเลิกการแชร์เป็นที่ต้องการเพื่อให้แน่ใจว่าไม่มีตัวแปรอื่น ๆ ถือไปยังอาร์เรย์เดียวกัน

var a = [1, 2, 3]
var b = a
b.unshare()
a[1] = 42
a               // [1, 42, 3]
b               // [1, 2, 3]

อืมสำหรับฉันแล้วunshare()วิธีการนั้นไม่ได้กำหนดไว้
Hlung

1
@Hlung มันถูกลบในเบต้า 3 ฉันได้อัปเดตคำตอบของฉันแล้ว
Pascal

12

ลักษณะการทำงานคล้ายกับArray.Resizeวิธีการใน. NET เพื่อให้เข้าใจสิ่งที่เกิดขึ้นอาจเป็นประโยชน์ในการดูประวัติของ.โทเค็นใน C, C ++, Java, C # และ Swift

ใน C โครงสร้างไม่มีอะไรมากไปกว่าการรวมตัวแปร การใช้.ตัวแปรประเภทโครงสร้างจะเข้าถึงตัวแปรที่เก็บไว้ภายในโครงสร้าง ตัวชี้ไปยังวัตถุที่ไม่ถือรวมตัวของตัวแปร แต่ระบุพวกเขา หากมีตัวชี้ที่ระบุโครงสร้างตัว->ดำเนินการอาจถูกใช้เพื่อเข้าถึงตัวแปรที่เก็บอยู่ภายในโครงสร้างที่ระบุโดยตัวชี้

ใน C ++ โครงสร้างและคลาสไม่เพียง แต่รวบรวมตัวแปรเท่านั้น แต่ยังสามารถแนบรหัสเข้ากับตัวแปรเหล่านั้นได้ ใช้.เพื่อเรียกวิธีการที่จะอยู่กับตัวแปรถามวิธีการที่จะทำหน้าที่อยู่กับเนื้อหาของตัวแปรตัวเอง ; การใช้->ตัวแปรที่ระบุวัตถุจะขอให้วิธีการนั้นดำเนินการกับวัตถุที่ระบุโดยตัวแปร

ใน Java ทุกประเภทตัวแปรที่กำหนดเองเพียงแค่ระบุวัตถุและการเรียกใช้วิธีการตามตัวแปรจะบอกวิธีการที่วัตถุจะถูกระบุโดยตัวแปร ตัวแปรไม่สามารถเก็บประเภทข้อมูลคอมโพสิตใด ๆ ได้โดยตรงและไม่มีวิธีการใดที่วิธีการเข้าถึงตัวแปรที่ถูกเรียกใช้ ข้อ จำกัด เหล่านี้แม้ว่าจะ จำกัด ทางความหมาย แต่ก็ลดความซับซ้อนของรันไทม์อย่างมาก การทำให้เข้าใจง่ายเช่นนี้ช่วยลดค่าใช้จ่ายทรัพยากรของ Java ในเวลาที่ตลาดมีความอ่อนไหวต่อปัญหาดังกล่าวและช่วยให้ตลาดได้รับแรงฉุดในตลาด พวกเขายังหมายความว่าไม่จำเป็นต้องมีโทเค็นเทียบเท่ากับที่.ใช้ใน C หรือ C ++ แม้ว่า Java สามารถใช้->ในลักษณะเดียวกับ C และ C ++ ผู้สร้างเลือกที่จะใช้อักขระเดียว. เนื่องจากไม่จำเป็นสำหรับวัตถุประสงค์อื่นใด

ในภาษา C # และ. NET อื่น ๆ ตัวแปรสามารถระบุวัตถุหรือเก็บประเภทข้อมูลคอมโพสิตโดยตรง เมื่อใช้กับตัวแปรของชนิดข้อมูลคอมโพสิตให้.ทำตามเนื้อหาของตัวแปร เมื่อใช้กับตัวแปรประเภทการอ้างอิงให้ดำเนิน.การกับวัตถุที่ระบุโดยมัน สำหรับการปฏิบัติการบางประเภทความแตกต่างทางความหมายไม่สำคัญอย่างยิ่ง แต่สำหรับสิ่งอื่น ๆ สถานการณ์ที่เป็นปัญหามากที่สุดคือกรณีที่วิธีการของชนิดข้อมูลแบบผสมซึ่งจะแก้ไขตัวแปรที่ถูกเรียกใช้นั้นจะถูกเรียกใช้บนตัวแปรแบบอ่านอย่างเดียว หากมีความพยายามในการเรียกใช้เมธอดบนค่าหรือตัวแปรแบบอ่านอย่างเดียวคอมไพเลอร์โดยทั่วไปจะคัดลอกตัวแปรปล่อยให้เมธอดดำเนินการตามนั้นและละทิ้งตัวแปร โดยทั่วไปจะปลอดภัยด้วยวิธีการที่อ่านได้เฉพาะตัวแปร แต่ไม่ปลอดภัยกับวิธีการที่เขียนลงไป น่าเสียดายที่. doo ยังไม่ได้มีวิธีการระบุวิธีการที่สามารถใช้กับการทดแทนดังกล่าวได้อย่างปลอดภัยและไม่สามารถทำได้

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

หากมีไทม์แมชชีนและกลับไปสู่การสร้าง C # และ / หรือ Swift เราสามารถหลีกเลี่ยงความสับสนรอบด้านได้โดยการใช้ภาษา.และ->โทเค็นอย่างใกล้ชิดกับการใช้ C ++ วิธีการของมวลรวมและประเภทการอ้างอิงสามารถใช้.เพื่อดำเนินการกับตัวแปรที่ถูกเรียกใช้และ->ดำเนินการตามค่า (สำหรับคอมโพสิต) หรือสิ่งที่ระบุไว้เช่นนั้น (สำหรับประเภทอ้างอิง) อย่างไรก็ตามทั้งสองภาษาได้รับการออกแบบในลักษณะนั้น

ใน C # การปฏิบัติตามปกติสำหรับวิธีการแก้ไขตัวแปรที่เรียกใช้คือการส่งตัวแปรเป็นrefพารามิเตอร์ไปยังเมธอด ดังนั้นการเรียกArray.Resize(ref someArray, 23);เมื่อsomeArrayระบุอาเรย์ขององค์ประกอบ 20 องค์ประกอบจะทำให้เกิดsomeArrayการระบุอาเรย์ใหม่จำนวน 23 องค์ประกอบโดยไม่มีผลกระทบต่ออาเรย์ดั้งเดิม การใช้refทำให้ชัดเจนว่าวิธีการที่ควรคาดว่าจะแก้ไขตัวแปรตามที่มันถูกเรียก ในหลายกรณีมีประโยชน์ที่จะสามารถแก้ไขตัวแปรได้โดยไม่ต้องใช้วิธีการคงที่ Swift address หมายถึงการใช้.ไวยากรณ์ ข้อเสียคือมันทำให้สูญเสียความกระจ่างเป็นวิธีการที่กระทำกับตัวแปรและวิธีการที่ทำหน้าที่ตามค่า


5

สำหรับฉันสิ่งนี้เหมาะสมกว่าหากคุณแทนที่ค่าคงที่ของคุณด้วยตัวแปร:

a[i] = 42            // (1)
e[i..j] = [4, 5]     // (2)

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

บรรทัดที่สองอาจซับซ้อนกว่านี้มาก ขึ้นอยู่กับค่าของiและjคุณอาจต้องจัดการหน่วยความจำ หากคุณคิดว่าeเป็นตัวชี้ที่ชี้ไปที่เนื้อหาของอาร์เรย์คุณจะไม่สามารถสรุปได้ว่ามันเป็นตัวชี้คงที่ คุณอาจต้องจัดสรรบล็อกหน่วยความจำใหม่คัดลอกข้อมูลจากบล็อกหน่วยความจำเก่าไปยังบล็อกหน่วยความจำใหม่และเปลี่ยนตัวชี้

ดูเหมือนว่านักออกแบบภาษาพยายามทำให้ (1) เบาที่สุดเท่าที่จะเป็นไปได้ เนื่องจาก (2) อาจเกี่ยวข้องกับการคัดลอกอยู่แล้วพวกเขาได้ใช้วิธีการแก้ปัญหาที่มักจะทำหน้าที่เหมือนคุณทำสำเนา

นี่เป็นเรื่องซับซ้อน แต่ฉันดีใจที่พวกเขาไม่ได้ทำให้มันซับซ้อนยิ่งขึ้นด้วยเช่นกรณีพิเศษเช่น"ถ้าใน (2) ฉันและ j เป็นค่าคงที่เวลาคอมไพล์และคอมไพเลอร์สามารถอนุมานได้ว่าขนาดของ e ไม่ไป การเปลี่ยนแปลงแล้วเราไม่ได้คัดลอก"


ในที่สุดจากความเข้าใจในหลักการออกแบบภาษาสวิฟต์ของฉันฉันคิดว่ากฎทั่วไปคือ:

  • ใช้ค่าคงที่ ( let) ทุกที่ทุกเวลาโดยค่าเริ่มต้นและจะไม่มีความประหลาดใจที่สำคัญ
  • ใช้ตัวแปร ( var) เฉพาะในกรณีที่จำเป็นอย่างยิ่งเท่านั้นและควรระมัดระวังในกรณีเหล่านั้นเนื่องจากจะมีความประหลาดใจ [ที่นี่: สำเนาของอาร์เรย์โดยนัยแปลก ๆ ในบางสถานการณ์ แต่ไม่ใช่ทุกสถานการณ์]

5

สิ่งที่ฉันได้พบคืออาร์เรย์จะเป็นสำเนาที่ไม่แน่นอนของหนึ่งอ้างอิงและถ้าหากการดำเนินการมีศักยภาพที่จะเปลี่ยนความยาวของอาเรย์ ในตัวอย่างสุดท้ายของคุณการf[0..2]ทำดัชนีโดยใช้หลาย ๆ การดำเนินการมีความเป็นไปได้ที่จะเปลี่ยนความยาวของมัน

var e = [1, 2, 3]
var f = e
e[0..2] = [4, 5]
e // 4,5,3
f // 1,2,3


var e1 = [1, 2, 3]
var f1 = e1

e1[0] = 4
e1[1] = 5

e1 //  - 4,5,3
f1 // - 4,5,3

8
"ถือว่าเป็นระยะเวลาที่มีการเปลี่ยนแปลง" ผมสามารถเข้าใจว่ามันจะได้รับการคัดลอก IFF ระยะเวลาที่มีการเปลี่ยนแปลง แต่ในการรวมกันโดยอ้างข้อความข้างต้นผมคิดว่านี่เป็น "คุณสมบัติ" ที่น่าเป็นห่วงจริงๆและหนึ่งซึ่งผมคิดว่าหลาย ๆ คนจะได้รับความผิด
Joel Berger

25
เพียงเพราะภาษาเป็นของใหม่ไม่ได้หมายความว่ามันจะไม่เป็นไรหากจะมีความขัดแย้งภายในที่ชัดเจน
Lightness Races ในวงโคจร

สิ่งนี้ได้รับการ "คงที่" ในรุ่นเบต้า 3 varตอนนี้อาร์เรย์สามารถเปลี่ยนแปลงได้อย่างสมบูรณ์และletอาร์เรย์ไม่มีการเปลี่ยนแปลงอย่างสมบูรณ์
ปาสกาล

4

สตริงและอาร์เรย์ของ Delphi มี "คุณสมบัติ" เหมือนกันทุกประการ เมื่อคุณดูการใช้งานมันสมเหตุสมผลแล้ว

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

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


4

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


1
ตอนนี้พฤติกรรม Array ใหม่มีให้บริการแล้วใน SDK ที่มาพร้อมกับ iOS 8 / Xcode 6 Beta 3
smileyborg

0

ฉันใช้. คัดลอก () สำหรับสิ่งนี้

    var a = [1, 2, 3]
    var b = a.copy()
     a[1] = 42 

1
ฉันได้รับ "Value of type '[Int]' ไม่มีสมาชิก 'copy'" เมื่อฉันเรียกใช้รหัสของคุณ
jreft56

0

มีการเปลี่ยนแปลงพฤติกรรมของอาร์เรย์ในรุ่น Swift ในภายหลังหรือไม่ ฉันแค่รันตัวอย่างของคุณ:

var a = [1, 2, 3]
var b = a
a[1] = 42
a
b

และผลลัพธ์ของฉันคือ [1, 42, 3] และ [1, 2, 3]

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