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

#to_s 또는 #to_str?Ruby에서 명시적으로 캐스팅 대 암시적으로 유형 강제 변환

형식 강제 변환은 개체의 형식을 해당 값과 함께 다른 형식으로 변경하는 것입니다. 예를 들어 #to_s를 사용하여 정수를 문자열로 변경 또는 #to_i를 사용하여 정수로 부동 . 덜 알려진 #to_str#to_int 일부 개체가 구현하는 메서드는 언뜻 보기에는 동일하지만 몇 가지 차이점이 있습니다.

이번 AppSignal 아카데미 에디션에서는 Ruby에서 유형을 명시적으로 캐스팅하고 암시적으로 강제하는 방법을 살펴보고 유형 캐스팅 액터에 대해 간략히 설명합니다. 우리는 두 방법의 차이점을 다루고 어떻게 사용하는지 논의할 것입니다.

먼저 명시적 캐스팅 도우미를 사용하여 Ruby에서 일반적으로 값을 다른 유형으로 강제 변환하는 방법을 먼저 살펴보겠습니다.

명시적 캐스팅 도우미

가장 일반적인 캐스팅 도우미는 #to_s입니다. , #to_i , #to_a#to_h . 이들은 명시적 캐스팅 방법입니다. 값을 한 유형에서 다른 유형으로 쉽게 변환하는 데 도움이 됩니다.

명시적 도우미는 분명한 약속을 가지고 옵니다. #to_s 때마다 개체에서 호출되면 항상 객체가 실제로 문자열로 잘 변환되지 않더라도 문자열을 반환합니다. 마이클 키튼을 배트맨으로 캐스팅하는 것과 같습니다. 코미디 배우가 그 역할에 특히 적합하지 않더라도 배트맨을 얻게 될 것입니다.

Ruby는 Ruby 표준 라이브러리의 거의 모든 기본 개체에 대해 이러한 도우미 메서드를 제공합니다.

:foo.to_s # => "foo"
10.0.to_i # => 10
"10".to_i # => 10

이러한 메서드, 특히 #to_s , Ruby의 가장 기본적인 유형에 구현됩니다. 캐스팅은 거의 항상 값을 반환하지만 결과는 예상한 것과 다를 수 있습니다.

"foo10".to_i          # => 0
[1, 2, 3].to_s        # => "[1, 2, 3]"
{ :foo => :bar }.to_s # => "{:foo=>:bar}"
{ :foo => :bar }.to_a # => [[:foo, :bar]]
Object.to_s           # => "Object"
Object.new.to_s       # => "#<Object:0x00007f8e6d053a90>"

#to_s 호출 , #to_i , #to_a#to_h 도우미는 선택한 유형에 값을 강제 적용합니다. 값에 어떤 일이 발생하는지에 관계없이 강제된 유형의 표현을 반환합니다.

암시적 강제 방법

우리가 캐스팅하는 형식처럼 작동하지 않는 값에 대한 형식 캐스팅 메서드를 호출하면 오류나 데이터 손실이 발생할 수 있습니다. Ruby는 또한 객체가 유형처럼 작동할 때만 값을 반환하는 암시적 강제 변환 방법을 제공합니다. 이렇게 하면 값이 우리가 원하는 유형처럼 작동하는지 확인할 수 있습니다. 이러한 암시적 강제 방법은 #to_str입니다. , #to_int , #to_ary#to_hash .

암묵적인 강압은 Leonard Nimoy를 Spock이 아닌 다른 역할로 캐스팅하는 것과 같습니다. 캐릭터가 Spock과 충분히 가까우면 작동하지만 그렇지 않으면 실패합니다. #to_str 도우미 시도 문자열로 변환하지만 NoMethodError가 발생합니다. 개체가 메서드를 구현하지 않고 암시적으로 강제할 수 없는 경우.

10.to_int                           # => 10
10.0.to_int                         # => 10
require "bigdecimal"
BigDecimal.new("10.0000123").to_int # => 10
 
# Unsuccessful coercions
"10".to_int             # => NoMethodError
"foo10".to_int          # => NoMethodError
[1, 2, 3].to_str        # => NoMethodError
{ :foo => :bar }.to_str # => NoMethodError
{ :foo => :bar }.to_ary # => NoMethodError
Object.to_str           # => NoMethodError
Object.new.to_str       # => NoMethodError

이제 Ruby가 요청한 유형을 강제하지 않고 수행하는 면에서 좀 더 엄격하다는 것을 알 수 있습니다. 강제 변환이 불가능한 경우 #to_* 메서드가 개체에 구현되지 않고 이를 호출하면 NoMethodError가 발생합니다. .

암시적 강제를 사용할 때 #to_str , 원래 유형이 String처럼 작동하는 경우에만 함수에 String 객체를 반환하도록 요청합니다. 이러한 이유로 #to_str Ruby 표준 라이브러리의 String에서만 구현됩니다.

Ruby가 암시적 강제를 사용하는 방법

강제 변환 중에 우리가 요구하는 것이 더 정확하다는 것 외에 암시적 강제가 유용한 다른 용도는 무엇입니까? Ruby는 상당한 시나리오에서 암시적 강제 변환을 사용합니다. 예를 들어 +로 개체를 결합할 때 .

name = "world!"
"Hello " + name # => "Hello world!"
 
# Without #to_str
class Name
  def initialize(name)
    @name = name
  end
end
"Hello " + Name.new("world!") # => TypeError: no implicit conversion of Name into String

여기에서 Ruby가 TypeError를 발생시키는 것을 볼 수 있습니다. Name에서 암시적 변환을 수행할 수 없기 때문에 String에 입력 .

#to_str을 구현하면 클래스에서 Ruby는 Name을(를) 강제 변환하는 방법을 알고 있습니다. 유형.

# With #to_str
class Name
  def to_str
    @name
  end
end
"Hello " + Name.new("world!") # => "Hello world!"

배열 및 #to_ary에서도 동일하게 작동합니다. .

class Options
  def initialize
    @internal = []
  end
 
  def <<(value)
    @internal << value
  end
end
 
options = Options.new
options << :foo
[:some_prefix] + options # => TypeError: no implicit conversion of Options into Array
 
class Options
  def to_ary
    @internal
  end
end
[:some_prefix] + options # => [:some_prefix, :foo]

하지만 #to_ary 더 많은 시나리오에서 사용됩니다. 이를 사용하여 Array를 별도의 변수로 구조화할 수 있습니다.

options = Options.new
options << :first
options << :second
options << :third
first, second, third = options
first  # => :first
second # => :second
third  # => :third

또한 객체를 블록 매개변수로 변환합니다.

[options].each do |(first, second)|
  first # => :first
  second # => :second
end

#to_hash와 같이 암시적 강제 방법이 사용되는 시나리오가 더 있습니다. ** 포함 . 이것은 #to_hash를 사용하여 값을 해시로 강제 변환합니다. parse_options에 전달하기 전에 방법.

class Options
  def to_hash
    # Create a hash from the Options Array
    Hash[*@internal]
  end
end
 
def parse_options(opts)
  opts
end
 
options = Options.new
options << :key
options << :value
parse_options(**options) # => {:key=>:value}

시행 유형

Ruby는 또한 유형이 알 수 없는 유형이고 올바른 유형을 가져오고자 할 때 보다 탄력적인 강제 변환 방법을 제공합니다. 모든 기본 유형(String(...) , Integer(...) , Float(...) , Array(...) , Hash(...) 등).

String(self)       # => "main"
String(self.class) # => "Object"
String(123456)     # => "123456"
String(nil)        # => ""
 
Integer(123.999)   # => 123
Integer("0x1b")    # => 27
Integer(Time.new)  # => 1204973019
Integer(nil)       # => TypeError: can't convert nil into Integer

String(...) 메소드는 먼저 #to_str 호출을 시도합니다. 값에 대해 실패하면 #to_s를 호출합니다. 방법. 모든 개체가 #to_str을 정의하는 것은 아닙니다. 따라서 암시적 강제 변환(#to_str ) 및 명시적(#to_s ) 캐스팅 방법을 사용하면 문자열 변환이 작동하고 원하는 값을 얻을 가능성이 높아집니다. 먼저 암시적 강제 변환을 호출하면 "#<Object:0x00007f8e6d053a90>"와 같은 값이 아닌 강제 변환된 유형의 값을 갖는 결과를 얻을 가능성이 더 높아집니다. .

class MyString
  def initialize(value)
    @value = value
  end
 
  def to_str
    @value
  end
end
 
s = MyString.new("hello world")
s.to_s    # => "#<MyString:0x...>"
s.to_str  # => "hello world"
String(s) # => "hello world"

강제된 유형처럼 작동하는 개체에 대해서만 암시적 캐스팅 방법을 구현해야 합니다. #to_str 자신의 String 클래스를 위해.

암시적 강제를 처음 시도하는 것 외에는 String(...) 도우미는 반환된 유형도 확인합니다. #to_str 문자열이 아닌 모든 유형의 값을 반환할 수 있는 메서드일 뿐입니다. 요청된 String(...) 유형의 값을 얻으려면 TypeError 발생 유형이 일치하지 않는 경우.

class MyString
  def to_str
    nil
  end
end
 
s = MyString.new("hello world")
s.to_s    # => "#<MyString:0x...>"
s.to_str  # => nil
String(s) # => "#<MyString:0x...>"

여기에서 Ruby가 #to_str의 결과를 무시한다는 것을 알 수 있습니다. nil을 반환했기 때문에 , 이는 String 유형이 아닙니다. 대신 #to_s 결과.

#to_s인 경우 nil도 반환합니다. 따라서 올바른 유형이 아닙니다. String(...) TypeError가 발생합니다. .

class MyString
  def to_str
    nil
  end
 
  def to_s
    nil
  end
end
 
s = MyString.new("hello world")
s.to_s    # => nil
s.to_str  # => nil
String(s) # => TypeError: can't convert MyString to String (MyString#to_s gives NilClass)

유형 강제를 적용하는 데 더 안정적일 수 있지만 캐스팅 도우미 메서드(String(...) , Integer(...) 등)은 주어진 값에 대해 더 많은 검사를 수행해야 하므로 일반적으로 약간 느립니다.

결론

개체에 대해 올바른 유형의 데이터를 처리하고 있는지 확인하려는 경우 유형 강제 변환이 유용한 프로세스입니다. 이 게시물에서 #to_s와 같은 명시적 캐스팅 도우미에 대한 지식을 새로 고쳤습니다. , #to_i , #to_a#to_h . 또한 #to_str와 같은 암시적 도우미가 있는 경우도 살펴보았습니다. , #to_int , #to_ary#to_hash 유용하고 Ruby 자체에서 사용하는 방법입니다.

이 유형 강제 변환 개요가 유용하고 액터 유형 캐스팅 비유를 찾은 방법을 찾았기를 바랍니다. 항상 그렇듯이 다루고 싶은 주제가 있으면 알려주십시오. 질문이나 의견이 있으시면 주저하지 말고 @AppSignal로 연락해 주십시오.