Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Ruby Freeze Method – ทำความเข้าใจเกี่ยวกับการกลายพันธุ์ของวัตถุ

วัตถุที่จะกลายพันธุ์หมายความว่าอย่างไร

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

พูดอีกอย่างก็คือ ไม่ใช่ทุกอ็อบเจกต์ใน Ruby ที่จะกลายพันธุ์ได้!

ตัวอย่างเช่น :

มันไม่สมเหตุสมผลเลยสำหรับตัวเลขหรือสัญลักษณ์ หรือแม้แต่ true หรือ false (ซึ่งเป็นวัตถุด้วย) ให้เปลี่ยนแปลง

หมายเลข 1 จะเป็น 1 เสมอ

แต่ออบเจ็กต์อื่นๆ โดยเฉพาะออบเจ็กต์ที่มีไว้เพื่อจัดเก็บข้อมูล เช่น ออบเจ็กต์ Array หรือ Hash ควรจะสามารถเปลี่ยนแปลงได้ด้วยเหตุผลด้านประสิทธิภาพ

ทางเลือกคืออะไร

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

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

ลองนึกภาพว่าคุณต้องคัดลอกอาร์เรย์องค์ประกอบหนึ่งล้าน (หรือมากกว่า) ทุกครั้งที่คุณต้องทำการเปลี่ยนแปลง ไม่สำคัญว่าจะเล็กน้อยแค่ไหน! ไม่ค่อยมีประสิทธิภาพ…

ยังไงก็ได้

มาดูวิธีการทำงานของ mutability ใน Ruby กันดีกว่า

การเปลี่ยนแปลงและตัวแปรเป็นตัวชี้

มีประเภทของข้อผิดพลาดในการเขียนโปรแกรมที่เกิดจากการรวมกันของสองสิ่ง:

  • วัตถุที่เปลี่ยนแปลงได้
  • ข้อเท็จจริงที่ว่าตัวแปรไม่มีข้อมูลโดยตรง แต่เป็นการอ้างอิงถึงตำแหน่งที่จัดเก็บข้อมูลนี้

วิธีหนึ่งที่ข้อผิดพลาดเหล่านี้แสดงให้เห็นคือเมื่อคุณพยายาม 'นามแฝง' ตัวแปร

นี่คือตัวอย่าง :

name       = "Peter"
other_name = name

puts other_name
# "Peter"

ในตัวอย่างนี้ ทั้ง name และ other_name มีการอ้างอิงไปยังวัตถุสตริงเดียวกัน คุณสามารถใช้เพื่อแสดงหรือแก้ไขเนื้อหาของสตริงนี้ได้

Ruby Freeze Method – ทำความเข้าใจเกี่ยวกับการกลายพันธุ์ของวัตถุ

ปัญหาจะปรากฏขึ้นหากเราปฏิบัติต่อ other_name เหมือนสำเนาของสตริง

other_name[0] = 'T'

name       # "Teter"
other_name # "Teter"

เนื่องจากตัวแปรทั้งสองชี้ไปที่สตริงเดียวกัน เราจึงเปลี่ยน "Peter" เป็น "Teter" นั่นเป็นปัญหาเพราะเราน่าจะอยากให้ “ปีเตอร์” อยู่ใกล้ๆ

การโคลนวัตถุ

วิธีหนึ่งที่จะจัดการกับปัญหานี้คือการใช้ dup วิธีการ

การดำเนินการนี้จะบอกให้ Ruby มอบสำเนาของวัตถุให้คุณ นอกจากนี้ยังมี clone เมธอด ซึ่งนอกจากจะให้สำเนาของอ็อบเจ็กต์แก่คุณแล้ว ยังคัดลอกสถานะการตรึง &เมธอดซิงเกิลตันใดๆ ที่กำหนดไว้บนอ็อบเจ็กต์

มาดูตัวอย่างกัน :

numbers = [1, 2, 3]

more_numbers = numbers.dup
more_numbers << 4

numbers      # [1, 2, 3]
more_numbers # [1, 2, 3, 4]

ในตัวอย่างนี้ คุณสามารถดูได้ว่า numbers เดิมเป็นอย่างไร อาร์เรย์ยังคงไม่เปลี่ยนแปลง ลองลบ dup . นั้นออก โทรไปสายที่สามแล้วมาดูกันว่าจะเป็นอย่างไร 🙂

วิธีการแช่แข็งทับทิม

อีกวิธีหนึ่งในการทำให้วัตถุปลอดภัยจากการเปลี่ยนแปลงที่ไม่ต้องการคือการ "หยุด" วัตถุนั้น วัตถุ Ruby ใดๆ จะถูกตรึงโดยใช้ freeze วิธีการ

เมื่อวัตถุถูกตรึง ความพยายามใดๆ ในการเปลี่ยนแปลงวัตถุนี้จะส่งผลให้ RuntimeError ข้อยกเว้น

หมายเหตุ:คุณสามารถใช้ frozen? วิธีการตรวจสอบว่าวัตถุถูกแช่แข็งหรือไม่

ตัวอย่าง :

animals = %w( cat dog tiger )
animals.freeze

animals << 'monkey'
# RuntimeError: can't modify frozen Array

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

animals[1][0] = 't'
# => ["cat", "tog", "tiger"]

หากคุณต้องการหยุดสตริง คุณต้องเรียก freeze กับพวกเขา ชอบสิ่งนี้:animals.each(&:freeze) .

สายแข็ง

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

Ruby จะสร้างออบเจ็กต์ใหม่ให้กับทุกๆ สตริง แม้ว่าสตริงสองสตริงจะมีลักษณะเหมือนกัน หรือกล่าวอีกนัยหนึ่ง พวกมันมี 'เนื้อหา' เหมือนกัน คุณสามารถเห็นสิ่งนี้เกิดขึ้นได้อย่างง่ายดายใน irb หากคุณใช้ object_id วิธีการ

นี่คือตัวอย่าง :

a = 'test'
b = 'test'

a.object_id # 76325640
b.object_id # 76317550

นี่เป็นปัญหาเนื่องจากอ็อบเจ็กต์เหล่านี้กำลังใช้หน่วยความจำพิเศษและรอบ CPU พิเศษ

เริ่มต้นด้วย Ruby 2.1 เมื่อคุณใช้ สตริงที่ค้าง , Ruby จะใช้วัตถุสตริงเดียวกัน เพื่อหลีกเลี่ยงการสร้างสำเนาใหม่ของสตริงเดียวกัน ซึ่งส่งผลให้ประหยัดหน่วยความจำและเพิ่มประสิทธิภาพเพียงเล็กน้อย

Rails ทำให้ กว้างขวาง การใช้สตริงที่ตรึงไว้ด้วยเหตุนี้ ตัวอย่างเช่น ลองดู PR นี้

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

หนึ่งคือการรวม # frozen_string_literal: true ที่ด้านบนของทุกไฟล์ที่คุณต้องการให้สตริงไม่เปลี่ยนรูป และอีกอย่างคือการใช้อาร์กิวเมนต์บรรทัดคำสั่ง --enable=frozen-string-literal .

สตริงที่ไม่เปลี่ยนรูปโดยค่าเริ่มต้นอาจจะลงจอดใน Ruby 3.0

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

รู้วิธีการของคุณ

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

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

ตัวอย่างสองวิธีของ 'ปัง' เหล่านี้คือ gsub! และ map! .

หมายเหตุ :

เมธอดที่ลงท้ายด้วย ! ไม่ได้หมายความว่าเป็น "วิธีการที่เปลี่ยนแปลงวัตถุ" เสมอไป

โดยทั่วไปแล้ว ! สัญลักษณ์ใช้เพื่อแสดงถึง 'อันตราย' ตัวอย่างหนึ่งตัวอย่าง นี่คือ exit! เมธอด ซึ่งจะออกจากโปรแกรมทันที โดยไม่สนใจตัวจัดการทางออก

นอกจากนี้ยังมีวิธีการที่เปลี่ยนวัตถุและไม่ได้ลงท้ายด้วย ! เครื่องหมาย. ตัวอย่างเช่น:delete , clear , push , concat และอีกมากมาย

บทสรุป

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

ฉันหวังว่าคุณจะพบว่าบทความนี้มีข้อมูล โปรดแบ่งปัน กับเพื่อนๆ ของคุณเพื่อที่พวกเขาจะได้เพลิดเพลิน มันเกินไป เข้าร่วมจดหมายข่าวของฉันด้านล่างด้วย คุณจะได้ไม่พลาดเนื้อหาแบบนี้เมื่อมันออกมา!