โดยทั่วไปแล้วข้อดีและข้อเสียของการใช้ OpenStruct เมื่อเปรียบเทียบกับโครงสร้างคืออะไร กรณีการใช้งานทั่วไปประเภทใดที่เหมาะสมกับแต่ละกรณี
โดยทั่วไปแล้วข้อดีและข้อเสียของการใช้ OpenStruct เมื่อเปรียบเทียบกับโครงสร้างคืออะไร กรณีการใช้งานทั่วไปประเภทใดที่เหมาะสมกับแต่ละกรณี
คำตอบ:
ด้วยOpenStruct
, คุณสามารถสร้างแอททริบิวต์ได้เอง Struct
บนมืออื่น ๆ ที่ต้องมีแอตทริบิวต์ที่กำหนดไว้เมื่อคุณสร้างมันขึ้นมา ตัวเลือกของตัวเลือกอื่น ๆ จะขึ้นอยู่กับว่าคุณจะต้องสามารถเพิ่มคุณสมบัติในภายหลังได้หรือไม่
วิธีที่จะคิดเกี่ยวกับพวกเขาคือเป็นจุดศูนย์กลางของสเปกตรัมระหว่างแฮชด้านหนึ่งและคลาสอื่น ๆ พวกเขาบอกเป็นนัยถึงความสัมพันธ์ที่เป็นรูปธรรมมากขึ้นในหมู่ข้อมูลมากกว่าที่จะทำ a Hash
แต่พวกเขาไม่มีวิธีอินสแตนซ์เหมือนคลาส ตัวอย่างของตัวเลือกสำหรับฟังก์ชั่นตัวอย่างเช่นใช้แฮช พวกมันเกี่ยวข้องกันอย่างหลวม ๆ ชื่อ, อีเมล์และหมายเลขโทรศัพท์ที่จำเป็นโดยฟังก์ชั่นจะได้รับการบรรจุเข้าด้วยกันในหรือStruct
OpenStruct
หากชื่ออีเมลและหมายเลขโทรศัพท์นั้นจำเป็นต้องใช้วิธีในการระบุชื่อในรูปแบบ "First Last" และ "Last, First" คุณควรสร้างคลาสเพื่อจัดการกับคลาสนั้น
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
วิธีการปรับแต่งโครงสร้างด้วยวิธีการคือการผ่านบล็อกเพื่อสร้าง (ที่มา ) แน่นอน { ... }
ว่าสามารถเขียนเป็นบล็อกหลายบรรทัด ( do ... end
) และฉันคิดว่านั่นเป็นวิธีที่ต้องการ
มาตรฐานอื่น ๆ :
require 'benchmark'
require 'ostruct'
REP = 100000
User = Struct.new(:name, :age)
USER = "User".freeze
AGE = 21
HASH = {:name => USER, :age => AGE}.freeze
Benchmark.bm 20 do |x|
x.report 'OpenStruct slow' do
REP.times do |index|
OpenStruct.new(:name => "User", :age => 21)
end
end
x.report 'OpenStruct fast' do
REP.times do |index|
OpenStruct.new(HASH)
end
end
x.report 'Struct slow' do
REP.times do |index|
User.new("User", 21)
end
end
x.report 'Struct fast' do
REP.times do |index|
User.new(USER, AGE)
end
end
end
สำหรับคนใจร้อนที่ต้องการทราบผลการเปรียบเทียบโดยไม่ต้องเรียกใช้ตัวเองนี่คือผลลัพธ์ของโค้ดข้างต้น (บน MB Pro 2.4GHz i7)
user system total real
OpenStruct slow 4.430000 0.250000 4.680000 ( 4.683851)
OpenStruct fast 4.380000 0.270000 4.650000 ( 4.649809)
Struct slow 0.090000 0.000000 0.090000 ( 0.094136)
Struct fast 0.080000 0.000000 0.080000 ( 0.078940)
UPDATE:
ในฐานะของ Ruby 2.4.1 OpenStruct และ Struct นั้นใกล้เคียงกับความเร็วมาก ดูhttps://stackoverflow.com/a/43987844/128421
ก่อนหน้านี้:
เพื่อความสมบูรณ์: Struct vs. Class vs. Hash vs. OpenStruct
ใช้งานโค้ดที่คล้ายกันกับของ burtlo บน Ruby 1.9.2, (1 จาก 4 แกน x86_64, RAM 8GB) [แก้ไขตารางเพื่อจัดแนวคอลัมน์]:
สร้าง 1 โครงสร้าง Mio: 1.43 วินาที, 219 MB / 90MB (อาศัย / res) สร้าง 1 Mio Class อินสแตนซ์: 1.43 วินาที, 219 MB / 90MB (virt / res) สร้าง 1 Mio Hashes: 4.46 วินาที, 493 MB / 364MB (อาศัย / res) สร้าง 1 Mio OpenStructs: 415.13 วินาที, 2464 MB / 2.3GB (virt / res) # ~ 100x ช้ากว่าแฮช สร้าง OpenStructs 100K: 10.96 วินาที, 369 MB / 242MB (อาศัย / res)
OpenStructs มีsloooooowและหน่วยความจำมากและไม่ได้ระดับดีสำหรับชุดข้อมูลขนาดใหญ่
การสร้าง 1 Mio OpenStructs เป็น~ 100x ช้ากว่าการสร้าง 1 Mio Hashes
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
กรณีการใช้งานสำหรับทั้งสองมีความแตกต่างกันมาก
คุณสามารถคิดถึงคลาส Struct ใน Ruby 1.9 ได้เทียบเท่ากับการstruct
ประกาศใน C ใน Ruby Struct.new
จะใช้ชื่อชุดของฟิลด์เป็นอาร์กิวเมนต์และส่งคืนคลาสใหม่ ในทำนองเดียวกันใน C การstruct
ประกาศใช้ชุดของเขตข้อมูลและอนุญาตให้โปรแกรมเมอร์ใช้ชนิดที่ซับซ้อนใหม่เช่นเดียวกับที่เขาต้องการชนิดในตัวใด ๆ
ทับทิม:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
ค:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
คลาส OpenStruct สามารถเปรียบเทียบกับการประกาศโครงสร้างแบบไม่ระบุชื่อใน C. ซึ่งอนุญาตให้โปรแกรมเมอร์สร้างอินสแตนซ์ของชนิดที่ซับซ้อน
ทับทิม:
o = OpenStruct.new(data1: 0, data2: 0)
o.data1 = 1
o.data2 = 2
ค:
struct {
int data1;
char data2;
} o;
o.data1 = 1;
o.data2 = 2;
นี่คือบางกรณีการใช้งานทั่วไป
OpenStructs สามารถใช้เพื่อแปลงแฮชให้เป็นวัตถุแบบครั้งเดียวซึ่งตอบสนองต่อคีย์แฮชทั้งหมดได้อย่างง่ายดาย
h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2
โครงสร้างจะมีประโยชน์สำหรับคำจำกัดความของชั้นเรียนชวเลข
class MyClass < Struct.new(:a,:b,:c)
end
m = MyClass.new
m.a = 1
OpenStructs ใช้หน่วยความจำมากขึ้นอย่างมากและช้ากว่านักแสดงเมื่อเทียบกับโครงสร้าง
require 'ostruct'
collection = (1..100000).collect do |index|
OpenStruct.new(:name => "User", :age => 21)
end
ในระบบของฉันรหัสต่อไปนี้ดำเนินการใน 14 วินาทีและใช้หน่วยความจำ 1.5 GB ไมล์สะสมของคุณอาจแตกต่างกันไป:
User = Struct.new(:name, :age)
collection = (1..100000).collect do |index|
User.new("User",21)
end
ซึ่งเกือบจะทันทีและใช้หน่วยความจำ 26.6 MB
Struct
:
>> s = Struct.new(:a, :b).new(1, 2)
=> #<struct a=1, b=2>
>> s.a
=> 1
>> s.b
=> 2
>> s.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>
OpenStruct
:
>> require 'ostruct'
=> true
>> os = OpenStruct.new(a: 1, b: 2)
=> #<OpenStruct a=1, b=2>
>> os.a
=> 1
>> os.b
=> 2
>> os.c
=> nil
ดูที่ API เกี่ยวกับวิธีการใหม่ ความแตกต่างมากมายสามารถพบได้ที่นั่น
โดยส่วนตัวแล้วฉันชอบ OpenStruct มากเพราะฉันไม่จำเป็นต้องกำหนดโครงสร้างของวัตถุไว้ก่อนและเพียงเพิ่มสิ่งต่าง ๆ ตามที่ฉันต้องการ ฉันเดาว่ามันจะเป็นข้อได้เปรียบหลัก (dis)?
ใช้รหัส @Robert ฉันเพิ่ม Hashie :: Mash ในรายการเบนช์มาร์กแล้วรับผลลัพธ์นี้:
user system total real
Hashie::Mash slow 3.600000 0.000000 3.600000 ( 3.755142)
Hashie::Mash fast 3.000000 0.000000 3.000000 ( 3.318067)
OpenStruct slow 11.200000 0.010000 11.210000 ( 12.095004)
OpenStruct fast 10.900000 0.000000 10.900000 ( 12.669553)
Struct slow 0.370000 0.000000 0.370000 ( 0.470550)
Struct fast 0.140000 0.000000 0.140000 ( 0.145161)
ไม่จริงคำตอบของคำถาม แต่อย่างที่สำคัญการพิจารณาถ้าคุณดูแลเกี่ยวกับประสิทธิภาพ โปรดสังเกตว่าทุกครั้งที่คุณสร้างการOpenStruct
ดำเนินการจะล้างแคชของเมธอดซึ่งหมายความว่าแอปพลิเคชันของคุณจะทำงานช้าลง ความช้าหรือไม่ได้OpenStruct
เป็นเพียงเกี่ยวกับการทำงานของตัวเองเท่านั้น แต่ความหมายที่ใช้พวกมันนำมาสู่แอปพลิเคชันทั้งหมด: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructs