문제

이것이 Ruby에서 가능한지 완전히 확신할 수는 없지만, 이를 수행하는 쉬운 방법이 있기를 바랍니다.변수를 선언하고 나중에 변수 이름을 알아내고 싶습니다.즉, 이 간단한 조각의 경우:

foo = ["goo", "baz"]

배열 이름(여기서는 "foo")을 어떻게 다시 얻을 수 있나요?실제로 가능하다면 모든 변수(예: 스칼라, 해시 등)에서 작동합니까?

편집하다:제가 기본적으로 하려는 일은 다음과 같습니다.나는 세 가지 중요한 변수가 있는 클래스를 둘러싸는 SOAP 서버를 작성 중이며 유효성 검사 코드는 기본적으로 다음과 같습니다.

  [foo, goo, bar].each { |param|
      if param.class != Array
        puts "param_name wasn't an Array. It was a/an #{param.class}"
        return "Error: param_name wasn't an Array"
      end
      }

내 질문은 다음과 같습니다.'param_name' 인스턴스를 foo, goo 또는 bar로 바꿀 수 있나요?이러한 개체는 모두 배열이므로 지금까지 받은 답변이 작동하지 않는 것 같습니다(모든 것을 리엔지니어링하는 것을 제외하고). dbr의 답변)

도움이 되었습니까?

해결책

문제를 뒤집어 보면 어떨까요?변수에서 이름을 가져오는 대신 이름에서 변수를 가져옵니다.

["foo", "goo", "bar"].each { |param_name|
  param = eval(param_name)
  if param.class != Array
    puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
    return "Error: #{param_name} wasn't an Array"
  end
  }

변수가 전혀 정의되지 않을 가능성이 있는 경우(배열이 아닌 것과 반대로) 평가를 유지하기 위해 "param = ..." 줄 끝에 "rescue nil"을 추가할 수 있습니다. 예외를 던지지 않고...

다른 팁

솔루션을 다시 설계해야 합니다.당신이 ~할 수 있었다 그렇게 하세요(당신은 할 수 없습니다). 그 질문에는 단순히 합리적인 대답이 없습니다.

get_name 메소드를 상상해보세요.

a = 1
get_name(a)

모두가 이것이 'a'를 반환해야 한다는 데 동의할 것입니다.

b = a
get_name(b)

'b', 'a' 또는 둘 다를 포함하는 배열을 반환해야 합니까?

[b,a].each do |arg|
  get_name(arg)
end

'arg', 'b' 또는 'a' 를 반환해야 합니까?

def do_stuff( arg )
  get_name(arg)
do
do_stuff(b)

'arg', 'b', 'a'를 반환해야 할까요? 아니면 이들 모두의 배열을 반환해야 할까요?배열을 반환하더라도 순서는 무엇이고 결과를 해석하는 방법을 어떻게 알 수 있습니까?

위의 모든 질문에 대한 답은 "내가 당시 내가 원하는 특정 것에 달려 있습니다"입니다. 루비의 문제를 어떻게 해결할 수 있는지 잘 모르겠습니다.

훨씬 쉬운 해결책이 있는 문제를 해결하려고 하는 것 같습니다.

왜 데이터를 해시에 저장하지 않는 걸까요?그렇다면 ..

data_container = {'foo' => ['goo', 'baz']}

..그러면 'foo' 이름을 얻는 것은 아주 사소한 일입니다.

즉, 문제에 대한 컨텍스트를 제공하지 않았으므로 이 작업을 수행할 수 없는 이유가 있을 수 있습니다.

[편집하다] 설명을 해보니 문제가 보이는데 이게 문제가 아닌 것 같네요..[foo, bar, bla]를 사용하면 다음과 같은 의미가 됩니다. ['content 1', 'content 2', 'etc'].실제 변수 이름은 전혀 관련이 없습니다.변수의 이름이 중요하다면 바로 이것이 해시가 존재하는 이유입니다.

문제는 [foo, bar] 등을 반복하는 것이 아니라 SOAP 서버가 데이터를 반환하는 방식 및/또는 이를 사용하려는 방식에 대한 근본적인 문제입니다.

제가 말하고 싶은 해결책은 SOAP 서버가 해시를 반환하도록 하거나 항상 세 가지 요소가 있다는 것을 알고 있으므로 다음과 같은 작업을 수행할 수 없는 것입니다.

{"foo" => foo, "goo" => goo, "bar"=>bar}.each do |param_name, param|
      if param.class != Array
        puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
        puts "Error: #{param_name} wasn't an Array"
      end
end

좋습니다. 인스턴스 메서드에서도 작동하며 특정 요구 사항(주석에 입력한 요구 사항)에 따라 다음을 수행할 수 있습니다.

local_variables.each do |var|
  puts var if (eval(var).class != Fixnum)
end

그냥 교체하세요 Fixnum 특정 유형 확인을 통해.

지역 변수 이름을 얻는 방법을 모르겠습니다.그러나 다음을 사용할 수 있습니다. instance_variables 메서드를 사용하면 개체의 모든 인스턴스 변수 이름 배열이 반환됩니다.

간단한 통화:

object.instance_variables

또는

self.instance_variables

모든 인스턴스 변수 이름의 배열을 가져옵니다.

구축 조쉬무어, 다음과 같은 것이 아마도 그렇게 할 것입니다:

# Returns the first instance variable whose value == x
# Returns nil if no name maps to the given value
def instance_variable_name_for(x)
  self.instance_variables.find do |var|
    x == self.instance_variable_get(var)
  end
end

있다 Kernel::local_variables, 그러나 이것이 메서드의 로컬 변수에 대해 작동할지는 확신할 수 없으며, 달성하려는 작업을 수행하는 방식으로 이를 조작할 수 있는지도 모르겠습니다.

좋은 질문입니다.나는 당신의 동기를 충분히 이해합니다.특정 상황에서 할당된 변수에 대한 지식을 갖는 특정 종류의 특수 객체가 있다는 점에 주목해 보겠습니다.이러한 특수 개체는 다음과 같습니다. Module 인스턴스, Class 인스턴스와 Struct 인스턴스:

Dog = Class.new
Dog.name # Dog

문제는 할당이 수행되는 변수가 상수일 때만 작동한다는 것입니다.(우리 모두는 Ruby 상수가 감정적으로 민감한 변수일 뿐이라는 것을 알고 있습니다.) 따라서:

x = Module.new # creating an anonymous module
x.name #=> nil # the module does not know that it has been assigned to x
Animal = x # but will notice once we assign it to a constant
x.name #=> "Animal"

어떤 변수가 할당되었는지 인식하는 객체의 이러한 동작을 일반적으로 호출합니다. 끊임없는 마법 (상수로 제한되기 때문입니다)하지만 이는 매우 바람직한 일이다 끊임없는 마법 특정 개체에만 작동합니다.

Rover = Dog.new
Rover.name #=> raises NoMethodError

다행스럽게도, 나는 보석을 썼다 y_support/name_magic, 그러면 이 작업이 자동으로 처리됩니다.

 # first, gem install y_support
require 'y_support/name_magic'

class Cat
  include NameMagic
end

사실 이것은 상수에서만 작동합니다(예:대문자로 시작하는 변수)는 그렇게 큰 제한은 아닙니다.실제로, 원하는 대로 개체에 이름을 지정하거나 지정하지 않을 자유가 있습니다.

tmp = Cat.new # nameless kitty
tmp.name #=> nil
Josie = tmp # by assigning to a constant, we name the kitty Josie
tmp.name #=> :Josie

불행히도 이것은 배열 리터럴에서는 작동하지 않습니다. 왜냐하면 배열 리터럴은 사용하지 않고 내부적으로 구성되기 때문입니다. #new 방법, NameMagic 의존합니다.따라서 원하는 것을 달성하려면 하위 클래스를 만들어야 합니다. Array:

require 'y_support/name_magic'
class MyArr < Array
  include NameMagic
end

foo = MyArr.new ["goo", "baz"] # not named yet
foo.name #=> nil
Foo = foo # but assignment to a constant is noticed
foo.name #=> :Foo

# You can even list the instances
MyArr.instances #=> [["goo", "baz"]]
MyArr.instance_names #=> [:Foo]

# Get an instance by name:
MyArr.instance "Foo" #=> ["goo", "baz"]
MyArr.instance :Foo #=> ["goo", "baz"]

# Rename it:
Foo.name = "Quux"
Foo.name #=> :Quux

# Or forget the name again:
MyArr.forget :Quux
Foo.name #=> nil

# In addition, you can name the object upon creation even without assignment
u = MyArr.new [1, 2], name: :Pair
u.name #=> :Pair
v = MyArr.new [1, 2, 3], ɴ: :Trinity
v.name #=> :Trinity

나는 끊임없는 마법 모방 행동을 달성했습니다. 모든 네임스페이스의 모든 상수 검색 현재 Ruby 객체 공간의 모습입니다.이로 인해 1초도 낭비되지 않지만 검색이 한 번만 수행되므로 개체가 해당 이름을 알아낸 후에는 성능 저하가 없습니다.앞으로 Ruby 핵심 팀은 약속했다 const_assigned.

그럴 수 없습니다. 다시 처음으로 돌아가 솔루션을 다시 설계해야 합니다.

Foo는 데이터에 대한 포인터를 보유하는 위치일 뿐입니다.데이터는 그것이 무엇을 가리키는지 전혀 모릅니다.Smalltalk 시스템에서는 VM에 객체에 대한 모든 포인터를 요청할 수 있지만 그렇게 하면 foo 자체가 아닌 foo 변수를 포함하는 객체만 얻을 수 있습니다.Ruby에서는 변수를 참조할 수 있는 실제 방법이 없습니다.한 답변에서 언급했듯이 데이터의 출처 등을 참조하는 태그를 데이터에 계속 배치할 수 있지만 일반적으로 이는 대부분의 문제에 대한 좋은 접근 방식이 아닙니다.해시를 사용하여 처음에 값을 받거나 해시를 사용하여 루프에 전달할 수 있으므로 DBR의 답변에서와 같이 유효성 검사 목적으로 인수 이름을 알 수 있습니다.

귀하의 질문에 대한 실제 답변에 가장 가까운 것은 각각 대신 Enumerable 메서드인 Each_with_index를 사용하는 것입니다.

my_array = [foo, baz, bar]
my_array.each_with_index do |item, index|
  if item.class != Array
    puts "#{my_array[index]} wasn't an Array. It was a/an #{item.class}"
  end
end

각각/each_with_index에 전달한 블록에서 return 문이 아무 것도 수행하지 않았거나 의미하지 않았기 때문에 제거했습니다.Each와 Each_with_index는 둘 다 작동 중인 배열을 반환합니다.

여기에서 주목할 만한 블록의 범위에 관한 내용도 있습니다.블록 외부에 변수를 정의한 경우 블록 내에서 사용할 수 있습니다.즉, 블록 내부에서 foo, bar, baz를 직접 참조할 수 있습니다.그 반대는 사실이 아닙니다.블록 내부에서 처음으로 생성한 변수는 블록 외부에서 사용할 수 없습니다.

마지막으로 do/end 구문은 여러 줄 블록에 선호되지만 이는 스타일의 문제일 뿐입니다. 비록 최근 빈티지의 루비 코드에서는 보편적이지만 말입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top