Secara umum, apa keuntungan dan kerugian menggunakan OpenStruct dibandingkan dengan Struct? Apa jenis kasus penggunaan umum yang cocok untuk masing-masing kasus ini?
Secara umum, apa keuntungan dan kerugian menggunakan OpenStruct dibandingkan dengan Struct? Apa jenis kasus penggunaan umum yang cocok untuk masing-masing kasus ini?
Jawaban:
Dengan OpenStruct
, Anda dapat membuat atribut secara sewenang-wenang. A Struct
, di sisi lain, harus memiliki atribut yang ditentukan ketika Anda membuatnya. Pilihan satu di atas yang lain harus didasarkan terutama pada apakah Anda harus dapat menambahkan atribut nanti.
Cara untuk berpikir tentang mereka adalah sebagai jalan tengah dari spektrum antara Hash di satu sisi dan kelas di sisi lain. Mereka menyiratkan hubungan yang lebih konkret antara data daripada Hash
, tetapi mereka tidak memiliki metode instan seperti halnya kelas. Banyak opsi untuk suatu fungsi, misalnya, masuk akal dalam hash; mereka hanya terkait longgar. Nama, email, dan nomor telepon yang dibutuhkan oleh suatu fungsi dapat dikemas bersama dalam suatu Struct
atau OpenStruct
. Jika nama, email, dan nomor telepon itu memerlukan metode untuk memberikan nama dalam format "First Last" dan "Last, First", maka Anda harus membuat kelas untuk menanganinya.
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
. ( sumber ) Tentu saja, { ... }
ada dapat ditulis sebagai blok multi-line ( do ... end
) dan, saya pikir, itulah cara yang disukai.
Tolok ukur lainnya:
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
Untuk yang tidak sabar yang ingin mendapatkan gambaran tentang hasil benchmark, tanpa menjalankannya sendiri, berikut adalah output dari kode di atas (pada 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)
MEMPERBARUI:
Pada Ruby 2.4.1 OpenStruct dan Struct lebih cepat dalam hal kecepatan. Lihat https://stackoverflow.com/a/43987844/128421
SEBELUMNYA:
Untuk kelengkapan: Struct vs. Class vs Hash vs OpenStruct
Menjalankan kode yang sama seperti burtlo's, di Ruby 1.9.2, (1 dari 4 core x86_64, 8GB RAM) [tabel diedit untuk menyelaraskan kolom]:
membuat 1 Mio Structs: 1,43 detik, 219 MB / 90MB (virt / res) membuat 1 instance Mio Class: 1,43 detik, 219 MB / 90MB (virt / res) membuat 1 Mio Hash: 4,46 detik, 493 MB / 364MB (virt / res) membuat 1 Mio OpenStructs: 415.13 detik, 2464 MB / 2.3GB (virt / res) # ~ 100x lebih lambat dari Hash membuat 100K OpenStructs: 10,96 detik, 369 MB / 242MB (virt / res)
OpenStructs adalah sloooooow dan memori intensif , dan tidak skala dengan baik untuk set data besar
Membuat 1 Mio OpenStructs adalah ~ 100x lebih lambat daripada membuat 1 Mio Hash .
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
Kasus penggunaan untuk keduanya sangat berbeda.
Anda bisa menganggap kelas Struct di Ruby 1.9 sebagai setara dengan struct
deklarasi di C. Di Ruby Struct.new
mengambil seperangkat nama bidang sebagai argumen dan mengembalikan Kelas baru. Demikian pula, dalam C, struct
deklarasi mengambil set bidang dan memungkinkan pemrogram untuk menggunakan tipe kompleks baru seperti yang ia lakukan pada tipe bawaan apa pun.
Rubi:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
C:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
Kelas OpenStruct dapat dibandingkan dengan deklarasi struct anonim dalam C. Ini memungkinkan programmer untuk membuat turunan dari tipe yang kompleks.
Rubi:
o = OpenStruct.new(data1: 0, data2: 0)
o.data1 = 1
o.data2 = 2
C:
struct {
int data1;
char data2;
} o;
o.data1 = 1;
o.data2 = 2;
Berikut adalah beberapa kasus penggunaan umum.
OpenStructs dapat digunakan untuk dengan mudah mengkonversi hash menjadi objek satu kali yang merespons semua kunci hash.
h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2
Struct dapat berguna untuk definisi kelas steno.
class MyClass < Struct.new(:a,:b,:c)
end
m = MyClass.new
m.a = 1
OpenStructs menggunakan lebih banyak memori dan berkinerja lebih lambat dibandingkan Structs.
require 'ostruct'
collection = (1..100000).collect do |index|
OpenStruct.new(:name => "User", :age => 21)
end
Pada sistem saya, kode berikut dijalankan dalam 14 detik dan menghabiskan memori 1,5 GB. Jarak tempuh Anda mungkin bervariasi:
User = Struct.new(:name, :age)
collection = (1..100000).collect do |index|
User.new("User",21)
end
Itu selesai hampir secara instan dan menghabiskan 26,6 MB memori.
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
Lihat API terkait metode baru. Banyak perbedaan dapat ditemukan di sana.
Secara pribadi, saya sangat menyukai OpenStruct, karena saya tidak harus mendefinisikan struktur objek sebelumnya, dan hanya menambahkan hal-hal yang saya inginkan. Saya kira itu akan menjadi keuntungan (dis) utama?
Menggunakan kode @Robert, saya menambahkan Hashie :: Mash ke item patokan dan mendapatkan hasil ini:
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)
Sebenarnya bukan jawaban untuk pertanyaan, tetapi pertimbangan yang sangat penting jika Anda peduli dengan kinerja . Harap perhatikan bahwa setiap kali Anda membuat OpenStruct
operasi menghapus cache metode, yang berarti aplikasi Anda akan berjalan lebih lambat. Kelambatan atau tidaknya OpenStruct
bukan hanya tentang cara kerjanya dengan sendirinya, tetapi implikasi yang menggunakan mereka membawa ke seluruh aplikasi: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructs