답변:
간단한 경험 법칙은 내부 식별자가 필요할 때마다 기호를 사용하는 것입니다. Ruby <2.2의 경우 메모리 누수를 방지하기 위해 동적으로 생성되지 않는 경우에만 기호를 사용합니다.
동적으로 생성되는 식별자에 사용하지 않는 유일한 이유는 메모리 문제 때문입니다.
이 질문은 많은 프로그래밍 언어에 기호가없고 문자열 만 있으므로 코드에서 식별자로도 사용되기 때문에 매우 일반적입니다. 당신은 심볼이 무엇을 걱정해야 될 운명 뿐만 아니라 당신이 기호를 사용해야 할 때 . 기호는 식별자를 의미합니다. 이 철학을 따르면 일을 올바르게 할 가능성이 있습니다.
기호와 문자열의 구현에는 몇 가지 차이점이 있습니다. 심볼의 가장 중요한 점은 불변 이라는 것입니다. 입니다. 이것은 그들이 그들의 가치를 결코 변하지 않을 것이라는 것을 의미합니다. 이 때문에 심볼은 문자열보다 빠르게 인스턴스화되며 두 심볼을 비교하는 것과 같은 일부 작업도 더 빠릅니다.
심볼이 변경 불가능하다는 사실로 인해 Ruby는 심볼을 참조 할 때마다 동일한 객체를 사용하여 메모리를 절약 할 수 있습니다. 따라서 인터프리터가 읽을 때마다 :my_key
다시 인스턴스화하는 대신 메모리에서 가져올 수 있습니다. 매번 새 문자열을 초기화하는 것보다 비용이 적게 듭니다.
다음 명령으로 이미 인스턴스화 된 모든 기호 목록을 가져올 수 있습니다 Symbol.all_symbols
.
symbols_count = Symbol.all_symbols.count # all_symbols is an array with all
# instantiated symbols.
a = :one
puts a.object_id
# prints 167778
a = :two
puts a.object_id
# prints 167858
a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!
puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.
2.2 이전의 Ruby 버전의 경우 심볼이 인스턴스화되면이 메모리는 다시 는 사용 가능 하지 않습니다 . 메모리를 해제하는 유일한 방법은 응용 프로그램을 다시 시작하는 것입니다. 따라서 기호는 잘못 사용되었을 때 메모리 누수의 주요 원인이기도합니다. 메모리 누수를 생성하는 가장 간단한 방법 to_sym
은 사용자 입력 데이터에 대한 방법 을 사용하는 것입니다.이 데이터는 항상 변경되므로 메모리의 새로운 부분이 소프트웨어 인스턴스에서 영원히 사용됩니다. Ruby 2.2는 기호 가비지 수집기를 도입했습니다. 동적으로 생성 된 심볼을 해제 . 따라서 심볼을 동적으로 생성하여 생성 된 메모리 누수는 더 이상 문제가되지 않습니다.
질문에 대한 답변 :
내 응용 프로그램이나 스크립트에 동일한 문자열이 두 개 이상 있으면 문자열 대신 기호를 사용해야한다는 것이 사실입니까?
찾고있는 것이 코드 내부에서 사용되는 식별자 인 경우 기호를 사용해야합니다. 출력물을 인쇄하는 경우 문자열이 두 번 이상 나타나더라도 메모리에 두 개의 다른 개체를 할당하더라도 문자열을 사용해야합니다.
이유는 다음과 같습니다.
@AlanDert : 햄 코드에서 % input {type : : checkbox} 같은 것을 여러 번 사용하면 체크 박스로 무엇을 사용해야합니까?
나 : 네.
@AlanDert :하지만 html 페이지에 기호를 인쇄하려면 문자열로 변환해야합니다. 그렇지 않나요? 그렇다면 그것을 사용하는 요점은 무엇입니까?
입력 유형은 무엇입니까? 사용하려는 입력 유형의 식별자 또는 사용자에게 보여주고 싶은 것?
언젠가는 HTML 코드가되는 것은 사실이지만 코드 줄을 작성하는 순간에는 식별자가된다는 의미입니다. 필요한 입력 필드의 종류를 식별합니다. 따라서 코드에서 반복해서 사용되며 항상 식별자와 동일한 "문자열"문자를 가지며 메모리 누수를 생성하지 않습니다.
즉, 문자열이 더 빠른지 확인하기 위해 데이터를 평가하지 않는 이유는 무엇입니까?
이것은 내가 이것을 위해 만든 간단한 벤치 마크입니다.
require 'benchmark'
require 'haml'
str = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: "checkbox"}').render
end
end.total
sym = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: :checkbox}').render
end
end.total
puts "String: " + str.to_s
puts "Symbol: " + sym.to_s
세 가지 출력 :
# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68
따라서 smbol을 사용하는 것이 실제로 문자열을 사용하는 것보다 약간 빠릅니다. 왜 그런 겁니까? HAML이 구현되는 방식에 따라 다릅니다. 확인하려면 HAML 코드를 약간 해킹해야하지만 식별자 개념에서 기호를 계속 사용하면 응용 프로그램이 더 빠르고 안정적입니다. 질문이 제기되면 벤치마킹하고 답을 얻으십시오.
간단히 말해서 기호는 문자로 구성된 이름이지만 변경할 수 없습니다. 반대로 문자열은 내용이 변경 될 수있는 문자에 대한 정렬 된 컨테이너입니다.
두 문자열을 비교하려면 잠재적으로 모든 문자를 살펴볼 필요가 있습니다. 길이가 N 인 두 문자열의 경우 N + 1 비교가 필요합니다 (컴퓨터 과학자가 "O (N) 시간"이라고 함).
def string_comp str1, str2
return false if str1.length != str2.length
for i in 0...str1.length
return false if str1[i] != str2[i]
end
return true
end
string_comp "foo", "foo"
그러나 : foo의 모든 모양은 동일한 객체를 참조하므로 객체 ID를보고 기호를 비교할 수 있습니다. 단일 비교 (컴퓨터 과학자들이 "O (1) 시간"이라고 함)로이를 수행 할 수 있습니다.
def symbol_comp sym1, sym2
sym1.object_id == sym2.object_id
end
symbol_comp :foo, :foo
C ++에서 "열거"를 사용하여 관련 상수 패밀리를 나타낼 수 있습니다.
enum BugStatus { OPEN, CLOSED };
BugStatus original_status = OPEN;
BugStatus current_status = CLOSED;
그러나 Ruby는 동적 언어이기 때문에 BugStatus 유형을 선언하거나 합법적 인 값을 추적하는 것에 대해 걱정할 필요가 없습니다. 대신 열거 형 값을 기호로 나타냅니다.
original_status = :open
current_status = :closed
3. Ruby 심볼은 일정하고 고유 한 이름입니다.
Ruby에서는 문자열의 내용을 변경할 수 있습니다.
"foo"[0] = ?b # "boo"
그러나 심볼의 내용은 변경할 수 없습니다.
:foo[0] = ?b # Raises an error
Ruby 함수에 키워드 인수를 전달할 때 기호를 사용하여 키워드를 지정합니다.
# Build a URL for 'bug' using Rails.
url_for :controller => 'bug',
:action => 'show',
:id => bug.id
일반적으로 해시 테이블의 키를 나타내는 기호를 사용합니다.
options = {}
options[:auto_save] = true
options[:show_comments] = false
다음은 codecademy에서 찾은 멋진 문자열 대 기호 벤치 마크입니다.
require 'benchmark'
string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]
string_time = Benchmark.realtime do
1000_000.times { string_AZ["r"] }
end
symbol_time = Benchmark.realtime do
1000_000.times { symbol_AZ[:r] }
end
puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."
출력은 다음과 같습니다.
String time: 0.21983 seconds.
Symbol time: 0.087873 seconds.
기호를 해시 키 식별자로 사용
{key: "value"}
기호를 사용하면 다른 순서로 메서드를 호출 할 수 있습니다.
def write (파일 :, 데이터 :, 모드 : "ascii") # 간결함을 위해 제거됨 종료 쓰기 (데이터 : 123, 파일 : "test.txt")
고정하여 문자열로 유지하고 메모리를 절약하십시오.
label = 'My Label'.freeze
/
(이후strings
) 을 제거해야합니다 . 여기있다 : www.reactive.io/tips/2009/01/11/the-difference-between-ruby- 상징 - 및 - 문자열