Nói chung, những lợi thế và bất lợi của việc sử dụng OpenSturation so với Struct là gì? Loại trường hợp sử dụng chung nào sẽ phù hợp với từng trường hợp này?
Nói chung, những lợi thế và bất lợi của việc sử dụng OpenSturation so với Struct là gì? Loại trường hợp sử dụng chung nào sẽ phù hợp với từng trường hợp này?
Câu trả lời:
Với một OpenStruct
, bạn có thể tùy ý tạo thuộc tính. Một Struct
, mặt khác, phải có thuộc tính của nó được xác định khi bạn tạo ra nó. Việc lựa chọn cái này hơn cái kia nên chủ yếu dựa vào việc bạn có cần thêm thuộc tính sau này hay không.
Cách nghĩ về chúng là nền tảng giữa của quang phổ giữa một bên và các lớp ở bên kia. Chúng ngụ ý một mối quan hệ cụ thể giữa các dữ liệu hơn là một Hash
, nhưng chúng không có các phương thức cá thể như một lớp. Một loạt các tùy chọn cho một chức năng, ví dụ, có ý nghĩa trong hàm băm; chúng chỉ liên quan một cách lỏng lẻo. Tên, email và số điện thoại cần thiết của một chức năng có thể được đóng gói cùng nhau trong một Struct
hoặc OpenStruct
. Nếu tên, email và số điện thoại đó cần các phương thức để cung cấp tên ở cả hai định dạng "Đầu tiên cuối cùng" và "Cuối cùng, Đầu tiên", thì bạn nên tạo một lớp để xử lý nó.
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
. ( nguồn ) Tất nhiên, { ... }
có thể được viết dưới dạng một khối nhiều dòng ( do ... end
) và, tôi nghĩ, đó là cách ưa thích.
Điểm chuẩn khác:
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
Đối với những người thiếu kiên nhẫn muốn có ý tưởng về kết quả điểm chuẩn, mà không tự chạy chúng, đây là đầu ra của mã ở trên (trên 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)
CẬP NHẬT:
Kể từ Ruby 2.4.1 OpenSturation và Struct gần hơn về tốc độ. Xem https://stackoverflow.com/a/43987844/128421
TRƯỚC
Để hoàn thiện: Struct vs. Class vs. Hash so với OpenSturation
Chạy mã tương tự như burtlo, trên Ruby 1.9.2, (1 trong 4 lõi x86_64, RAM 8GB) [bảng được chỉnh sửa để căn chỉnh các cột]:
tạo 1 Mio Structs: 1,43 giây, 219 MB / 90MB (virt / res) tạo các phiên bản 1 Mio Class: 1.43 giây, 219 MB / 90MB (virt / res) tạo 1 Mio Băm: 4,46 giây, 493 MB / 364MB (virt / res) tạo 1 Mio OpenStructs: 415,13 giây, 2464 MB / 2.3GB (virt / res) # ~ 100 lần chậm hơn so với Băm tạo 100K OpenStructs: 10,96 giây, 369 MB / 242MB (virt / res)
OpenStructs là sloooooow và bộ nhớ chuyên sâu , và không mở rộng tốt cho các tập dữ liệu lớn
Tạo 1 Mio OpenStructs chậm hơn ~ 100 lần so với tạo 1 Mio Hashing .
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
Các trường hợp sử dụng cho hai là khá khác nhau.
Bạn có thể nghĩ về lớp Struct trong Ruby 1.9 tương đương với struct
khai báo trong C. Trong Ruby Struct.new
lấy một tập hợp các tên trường làm đối số và trả về một Class mới. Tương tự, trong C, một struct
khai báo lấy một tập các trường và cho phép lập trình viên sử dụng loại phức tạp mới giống như bất kỳ loại tích hợp nào.
Ruby:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
C:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
Lớp OpenSturation có thể được so sánh với một khai báo cấu trúc ẩn danh trong C. Nó cho phép lập trình viên tạo một thể hiện của một kiểu phức tạp.
Ruby:
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;
Dưới đây là một số trường hợp sử dụng phổ biến.
OpenStructs có thể được sử dụng để dễ dàng chuyển đổi băm thành các đối tượng một lần đáp ứng tất cả các khóa băm.
h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2
Cấu trúc có thể hữu ích cho các định nghĩa lớp tốc ký.
class MyClass < Struct.new(:a,:b,:c)
end
m = MyClass.new
m.a = 1
OpenStructs sử dụng nhiều bộ nhớ hơn và hoạt động chậm hơn so với Structs.
require 'ostruct'
collection = (1..100000).collect do |index|
OpenStruct.new(:name => "User", :age => 21)
end
Trên hệ thống của tôi, đoạn mã sau được thực thi trong 14 giây và tiêu tốn 1,5 GB bộ nhớ. Số dặm của bạn có thể thay đổi:
User = Struct.new(:name, :age)
collection = (1..100000).collect do |index|
User.new("User",21)
end
Điều đó đã hoàn thành gần như ngay lập tức và tiêu thụ 26,6 MB bộ nhớ.
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
Hãy xem API liên quan đến phương pháp mới. Rất nhiều sự khác biệt có thể được tìm thấy ở đó.
Cá nhân, tôi khá thích OpenSturation, vì tôi không phải xác định cấu trúc của đối tượng trước và chỉ cần thêm công cụ theo ý muốn. Tôi đoán đó sẽ là lợi thế chính (dis) của nó?
Sử dụng mã @Robert, tôi thêm Hashie :: Mash vào mục chuẩn và nhận được kết quả này:
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)
Không thực sự là một câu trả lời cho câu hỏi, nhưng một xem xét rất quan trọng nếu bạn quan tâm đến hiệu suất . Xin lưu ý rằng mỗi khi bạn tạo một OpenStruct
thao tác sẽ xóa bộ đệm phương thức, có nghĩa là ứng dụng của bạn sẽ hoạt động chậm hơn. Sự chậm chạp hay không OpenStruct
không chỉ là về cách thức hoạt động của nó, mà là những hàm ý mà việc sử dụng chúng mang lại cho toàn bộ ứng dụng: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructs