형식 강제 변환은 개체의 형식을 해당 값과 함께 다른 형식으로 변경하는 것입니다. 예를 들어 #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로 연락해 주십시오.