이 기사에서는 객체 마샬링에 대해 알아보겠습니다. 그것이 무엇인지 설명하고 Marshall 모듈을 살펴본 다음 예제를 살펴보겠습니다. 그런 다음 한 단계 더 나아가 _dump
를 비교하겠습니다. 및 self._load
행동 양식. 가자!
객체 마샬링이란 무엇입니까?
코드를 작성할 때 객체를 저장하고 다른 프로그램으로 전송하거나 다음 프로그램 실행에서 재사용할 수 있습니다. 예를 들어, 개체 마샬링은 Sidekiq에서 사용됩니다. Sidekiq 작업이 Ruby on Rails 애플리케이션에서 대기열에 추가되면 이 작업의 직렬화가 Redis에 삽입됩니다. 그러면 Sidekiq 프로세스가 이 JSON을 역직렬화하고 JSON에서 원래 작업을 재구성할 수 있습니다.
컴퓨터 프로그래밍에서 객체의 직렬화 및 역직렬화 프로세스를 일반적으로 객체 마샬링이라고 합니다. . 이제 Ruby가 객체 마샬링을 처리하기 위해 기본적으로 제공하는 것을 살펴보겠습니다.
마샬 모듈
Ruby는 완전한 객체 지향 프로그래밍 언어이므로 Marshall
을 사용하여 객체를 직렬화하고 저장하는 방법을 제공합니다. 표준 라이브러리에 있는 모듈. 다른 Ruby 프로세스에서 저장 및 역직렬화할 수 있는 바이트 스트림으로 개체를 직렬화할 수 있습니다.
이제 문자열을 직렬화하고 직렬화된 객체를 자세히 살펴보겠습니다.
hello_world = 'hello world!'
serialized_string = Marshal.dump(hello_world) # => "\x04\bI\"\x11hello world!\x06:\x06ET"
serialized_string.class # => String
deserialized_hello_world = Marshal.load(serialized_string) # => "hello world!"
hello_world.object_id # => 70204420126020
deserialized_hello_world.object_id # => 70204419825700
그런 다음 Marshal.dump
를 호출합니다. 우리의 문자열을 직렬화하는 모듈 메소드. 직렬화된 문자열을 포함하는 반환 값을 serialized_string
에 저장합니다. 변하기 쉬운. 이 문자열은 파일에 저장할 수 있으며 파일을 재사용하여 다른 프로세스에서 원래 개체를 재구성할 수 있습니다. 그런 다음 Marshal.load
를 호출합니다. 바이트 스트림에서 원본 개체를 재구성하는 메서드입니다.
새로 재구성된 이 문자열에는 다른 object_id
가 있음을 알 수 있습니다. hello_world
보다 이는 다른 개체이지만 동일한 데이터를 포함한다는 것을 의미합니다.
정말 멋진! 하지만 Marshal
은 모듈이 문자열을 재구성할 수 있습니까? 그리고 직렬화 및 역직렬화할 속성을 제어하려면 어떻게 해야 합니까?
객체 마샬링의 구체적인 예
이 질문에 답하기 위해 User
라는 사용자 지정 구조체에 마샬링 전략을 구현해 보겠습니다. .
User = Struct.new(:fullname, :age, :roles)
user = User.new('Mehdi Farsi', 42, [:admin, :operator])
User
구조체는 3가지 속성을 정의합니다. fullname
, age
및 roles
. 이 예에는 다음 기준과 일치하는 경우에만 직렬화하는 비즈니스 규칙이 있습니다.
fullname
64자 미만 포함roles
배열에:admin
이 포함되어 있지 않습니다. 역할
이를 위해 User#marshal_dump
를 정의할 수 있습니다. 커스텀 직렬화 전략을 구현하는 방법입니다. 이 메소드는 Marshal.dump
를 호출할 때 호출됩니다. User
인스턴스가 있는 메소드 구조체를 매개변수로 사용합니다. 이 메서드를 정의해 보겠습니다.
User = Struct.new(:age, :fullname, :roles) do
def marshal_dump
{}.tap do |result|
result[:age] = age
result[:fullname] = fullname if fullname.size <= 64
result[:roles] = roles unless roles.include? :admin
end
end
end
user = User.new(42, 'Mehdi Farsi', [:admin, :operator])
user_dump = Marshal.dump(user) # 'in User#marshal_dump'
user_dump # => "\x04\bU:\tUser{\a:\bageI\"\x10Mehdi Farsi\x06:\x06ET:\rfullnamei/"
위의 예에서 User#marshal_dump
메서드는 Marshal.dump(user)를 호출할 때 호출됩니다. user_dump
변수는 User
의 직렬화인 문자열을 포함합니다. 인스턴스.
이제 덤프가 있으므로 사용자를 재구성하기 위해 역직렬화해 보겠습니다. 이를 위해 User#marshal_load
를 정의합니다. User
의 역직렬화 전략을 구현하는 메소드 덤프.
따라서 이 메서드를 정의해 보겠습니다.
User = Struct.new(:age, :fullname, :roles) do
def marshal_dump
{}.tap do |result|
result[:age] = age
result[:fullname] = fullname if fullname.size <= 64
result[:roles] = roles unless roles.include? :admin
end
end
def marshal_load(serialized_user)
self.age = serialized_user[:age]
self.fullname = serialized_user[:fullname]
self.roles = serialized_user[:roles] || []
end
end
user = User.new(42, 'Mehdi Farsi', [:admin, :operator])
user_dump = Marshal.dump(user) # 'in User#marshal_dump'
user_dump # => "\x04\bU:\tUser{\a:\bagei/:\rfullnameI\"\x10Mehdi Farsi\x06:\x06ET"
original_user = Marshal.load(user_dump) # 'in User#marshal_load'
original_user # => #<struct User age=42, fullname="Mehdi Farsi", roles=[]>
위의 예에서 User#marshal_load method
가 Marshal.load(user_dump)
를 호출할 때 호출됩니다. . original_user
변수는 사용자 인스턴스의 재구성인 구조체를 포함합니다.
original_user.roles
user.roles
와 유사하지 않습니다. 직렬화 동안 이후의 배열, user.roles
:admin
포함 역할. 따라서 user.roles
user_dump
로 직렬화되지 않았습니다. 변수.
_dump 및 self._load 메소드
Marshal.dump
일 때 및 Marshal.load
이 메서드는 marshal_dump
를 호출합니다. 및 marshal_load
이 메서드의 매개변수로 전달된 개체의 메서드입니다.
하지만 Marshal.dump
및 Marshal.load
메소드는 _dump
라는 두 개의 다른 메소드를 호출하려고 시도합니다. 및 self._load
매개변수로 전달된 개체에 대해?
_dump 메소드
marshal_dump
의 차이점 및 _dump
방법은 다음과 같습니다.
_dump
를 사용할 때 더 낮은 수준에서 직렬화 전략을 처리해야 합니다. 메서드 — 직렬화할 데이터를 나타내는 문자열을 반환해야 합니다.marshal_dump
메소드가_dump
보다 우선합니다. 둘 다 정의된 경우
다음 예를 살펴보겠습니다.
User = Struct.new(:age, :fullname, :roles) do
def _dump level
[age, fullname].join(':')
end
end
user = User.new(42, 'Mehdi Farsi', [:admin, :operator])
Marshal.dump(user) # => "\x04\bIu:\tUser\x1342:Mehdi Farsi\x06:\x06EF"
User#_dump
에서 메서드를 사용하려면 직렬화 개체를 인스턴스화하고 반환해야 합니다. 는 직렬화를 나타내는 문자열입니다.
다음 예에서는 User#marshal_dump
를 정의합니다. 및 User#_dump
메소드를 호출하고 어떤 메소드가 호출되었는지 확인하기 위해 문자열을 반환합니다.
User = Struct.new(:age, :fullname, :roles) do
def marshal_dump
'in User#marshal_dump'
end
def _dump level
'in User#_dump'
end
end
user = User.new(42, 'Mehdi Farsi', [:admin, :operator])
user_dump = Marshal.dump(user) # "in User#marshal_dump"
User#marshal_dump
둘 다 정의된 경우에도 호출됩니다.
self._load 메소드
이제 marshal_load
를 살펴보겠습니다. 및 _load
방법.
marshal_load
의 차이점 및 _load
방법은 다음과 같습니다.
_load
를 사용할 때 더 낮은 수준에서 역직렬화 전략을 처리해야 합니다. method — 원본 개체의 인스턴스화를 담당하고 있습니다.marshal_load
메소드는_self.load
때 역직렬화된 객체를 인수로 사용합니다. 메서드는 직렬화된 문자열을 인수로 사용합니다.marshal_load
메소드는self._load
일 때 인스턴스 메소드입니다. 클래스 메서드입니다.
다음 예를 살펴보겠습니다.
User = Struct.new(:age, :fullname, :roles) do
def _dump level
[age, fullname].join(':')
end
def self._load serialized_user
user_info = serialized_user.split(':')
new(*user_info, Array.new)
end
end
user = User.new(42, 'Mehdi Farsi', [:admin, :operator])
user_dump = Marshal.dump(user)
user_dump # => "\x04\bIu:\tUser\x1342:Mehdi Farsi\x06:\x06EF"
original_user = Marshal.load(user_dump)
original_user # => #<struct User age="Mehdi Farsi", fullname=42, roles=[]>
User._load
에서 방법:
User#_dump
가 반환한 문자열을 역직렬화합니다. 방법- 새로운
User
를 인스턴스화합니다. 역직렬화된 정보 전달
원래 사용자를 재구성하는 데 사용된 개체를 할당하고 인스턴스화하는 작업을 담당하고 있음을 알 수 있습니다.
따라서 Marshal.load
marshal_load
에 결합됨 재구성된 원본 개체의 인스턴스화를 처리합니다. 그런 다음 marshal_load
를 호출합니다. 새로 인스턴스화된 개체에 대한 인수로 전달된 직렬화된 개체가 있는 메서드입니다.
반대로 Marshal.load
에 대한 호출은 _load
에 결합됨 self._load
클래스 메소드 담당:
_dump
에서 반환된 데이터 역직렬화 방법- 재구성된 원본 개체 인스턴스화
결론
필요에 따라 더 높거나 더 낮은 직렬화/역직렬화 전략을 구현할 수 있습니다. 이렇게 하려면 적절한 Marshal 후크 메서드와 결합된 Marshal 모듈을 사용할 수 있습니다.
짜잔!