Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby의 객체 마샬링

이 기사에서는 객체 마샬링에 대해 알아보겠습니다. 그것이 무엇인지 설명하고 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 , ageroles . 이 예에는 다음 기준과 일치하는 경우에만 직렬화하는 비즈니스 규칙이 있습니다.

  • 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 methodMarshal.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.dumpMarshal.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 모듈을 사용할 수 있습니다.

짜잔!