Elixir에서 변수 유형을 확인하는 방법


138

Elixir에서는 파이썬과 같은 유형을 어떻게 확인합니까?

>>> a = "test"
>>> type(a)
<type 'str'>
>>> b =10
>>> type(b)
<type 'int'>

Elixir에는 'is_bitstring', 'is_float', 'is_list', 'is_map'등과 같은 유형 검사기가 있지만 유형이 무엇인지 모를 경우 어떻게해야합니까?

답변:


104

Elixir / Erlang에서 변수 유형을 얻는 직접적인 방법은 없습니다.

일반적으로 변수의 유형을 알고 그에 따라 작동합니다. is_*변수 유형에 따라 작동하기 위해 함수를 사용할 수 있습니다 .

일부 Erlang은 Erlang (및 Elixir) 입력에 관한 장을 제공 합니다.

is_*함수 패밀리 를 사용하는 가장 관용적 인 방법 은 패턴 일치에서 사용하는 것입니다.

def my_fun(arg) when is_map(arg), do: ...
def my_fun(arg) when is_list(arg), do: ...
def my_fun(arg) when is_integer(arg), do: ...
# ...and so on

3
Erlang / Elixir에 실제로 저장된 유형 정보가 없습니까? 언어를 사용하려면 기존 유형보다 완전히 새로운 래퍼를 만들어야합니까? Oo
Dmitry

2
@Dmitry 사용 가능하다는 것은 무엇을 의미합니까? 다음과 같은 결과를 사용할 구체적인 예를 볼 수 있습니까 typeof(variable)?
whatyouhide

1
프로그램이 컴파일 시간을 떠나 런타임에 들어가면 일부 개체가 손실 된 내용에 대한 모든 정보가 손실됩니다. 실행중인 프로그램의 정보를 검사하고 싶을 때 진행 상황을 알 수있는 유일한 방법은 맵 네트워크를 통해 노출되는 것을 검사하는 것입니다. 유형 정보를 사용할 수없고 유형을 검사하려면 유형이 이미 노출 된 경우보다 유형을 얻기 위해 객체를 분석하는 데 훨씬 더 많은 비용이 듭니다. typeof를 사용하면 실행중인 시스템을 분석하고 유형 검사 및 다형성을 허용하는 방식으로 런타임에 확장 할 수 있습니다.
Dmitry

2
더 구체적으로; typeof의 가장 유용한 사용법은 [type string, function]의 해시 테이블을 알 수없는 목록에 직접 매핑하는 기능입니다. 예를 들어; IO.puts는 [1,2, 3]이 문자로 읽히고 (왜 erlang !!?) foo = [1, "hello", [1, 2, 3]]코드를 사용하여 코드 위에 매핑 될 수 없으며 Enum.map(foo, fn(x) -> IO.puts x end), 당신에게 작은 얼굴들을 보여줄 것입니다 (시도하십시오!). 따라서 목록이 목록 인 경우에만 검사가 필요하지만 대부분의 경우 필요하지 않은 경우에도 검사를 사용해야합니다. typeof를 사용하면 if 문 (O (n))을 사전 조회 (O (1))로 바꿀 수 있습니다.
Dmitry

1
이러한 유형의 사용을 위해 @Dmitry Elixir 프로토콜이 유용 할 것입니다. elixir-lang.org/getting-started/protocols.htmlPrintable 정수 목록과 같이 인쇄 동작을 래핑하고 변경하는 자체 프로토콜을 구현할 수 있습니다 . Erlang 코드와 함께 사용하지 마십시오. 메시지 대신 정수 목록이 표시되는 이유를 궁금해 할 것입니다.
매트 Jadczak

168

elixir 1.2부터는 iiex에 유형과 더 많은 Elixir 변수를 나열 하는 명령이 있습니다.

iex> foo = "a string" 
iex> i foo 
Term
 "a string"
Data type
 BitString
Byte size
 8
Description
 This is a string: a UTF-8 encoded binary. It's printed surrounded by
 "double quotes" because all UTF-8 encoded codepoints in it are        printable.
Raw representation
  <<97, 32, 115, 116, 114, 105, 110, 103>>
Reference modules
  String, :binary

i명령 의 코드를 보면 이것이 프로토콜을 통해 구현되었음을 알 수 있습니다.

https://github.com/elixir-lang/elixir/blob/master/lib/iex/lib/iex/info.ex

Elixir에서 모든 데이터 유형에 대한 함수를 구현하려는 경우 기능을 수행하려는 모든 데이터 유형에 대한 프로토콜 및 프로토콜 구현을 정의하는 방법입니다. 안타깝게도 경비원에서는 프로토콜 기능을 사용할 수 없습니다. 그러나 간단한 "유형"프로토콜은 구현하기가 매우 간단합니다.


1
2019 년에 이것은 오류를 반환합니다 undefined function i/1
-info

1
이것은 여전히 ​​Elixir 1.8.1에서 작동합니다. 아주 오래된 버전의 엘릭서가 설치되어 있어야합니다.
Fred the Magic Wonder Dog

2
@krivar @ fred-the-magic-wonder-dog 당신은 둘 다 맞습니다 :). &i/1의 기능입니다 IEx.Helpers. &IEx.Helpers.i/1바닐라 엘릭서에 넣으면 에 응용 프로그램으로 CompileError포함되지 않은 경우를 생성 :iex합니다 mix.exs.
popedotninja

39

또한 디버깅 목적으로 iex가 아닌 경우 직접 호출 할 수 있습니다.

IEx.Info.info(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]

1
당신의 로그에 그것을보고 싶다면 IO.inspect (IEx.Info.info (5))를 추가하십시오
Guillaume

24

또 다른 방법은 패턴 일치를 사용하는 것입니다. %DateTime{}구조체 를 사용하는 Timex를 사용하고 있고 요소가 하나인지 알고 싶다고 가정 해보십시오 . 메소드에서 패턴 일치를 사용하여 일치를 찾을 수 있습니다.

def is_a_datetime?(%DateTime{}) do
  true
end

def is_a_datetime?(_) do
  false
end

1
또는 허용 된 답변이 언급되었지만 스트레스를받지 않았을 때 :»일반적으로 그에 따라 행동하기 위해 변수의 유형을 알고 싶어합니다«. Elixir에서는 switch/가 아닌 패턴 일치에 따라 작동 case합니다.
mariotomo 2016

18

누군가가 실제로 제정신 버전을 알아 내기 위해 여기에 남겨 두겠습니다. 현재 Google에 나오는 좋은 답변은 없습니다 ...

defmodule Util do
    def typeof(self) do
        cond do
            is_float(self)    -> "float"
            is_number(self)   -> "number"
            is_atom(self)     -> "atom"
            is_boolean(self)  -> "boolean"
            is_binary(self)   -> "binary"
            is_function(self) -> "function"
            is_list(self)     -> "list"
            is_tuple(self)    -> "tuple"
            true              -> "idunno"
        end    
    end
end

완전성을 위해 테스트 사례 :

cases = [
    1.337, 
    1337, 
    :'1337', 
    true, 
    <<1, 3, 3, 7>>, 
    (fn(x) -> x end), 
    {1, 3, 3, 7}
]

Enum.each cases, fn(case) -> 
    IO.puts (inspect case) <> " is a " <> (Util.typeof case)
end

프로토콜이있는 솔루션은 다음과 같습니다. 나는 그들이 더 빠르면 확실하지 않습니다 (모든 유형에 대해 루프를 수행하지 않기를 바랍니다). 그러나 그것은 매우 추악합니다 (깨지기 쉽습니다; 기본 유형을 추가하거나 제거하거나 이름을 바꾸면 깨질 것입니다).

defprotocol Typeable, do: def typeof(self)
defimpl Typeable, for: Atom, do: def typeof(_), do: "Atom"
defimpl Typeable, for: BitString, do: def typeof(_), do: "BitString"
defimpl Typeable, for: Float, do: def typeof(_), do: "Float"
defimpl Typeable, for: Function, do: def typeof(_), do: "Function"
defimpl Typeable, for: Integer, do: def typeof(_), do: "Integer"
defimpl Typeable, for: List, do: def typeof(_), do: "List"
defimpl Typeable, for: Map, do: def typeof(_), do: "Map"
defimpl Typeable, for: PID, do: def typeof(_), do: "PID"
defimpl Typeable, for: Port, do: def typeof(_), do: "Port"
defimpl Typeable, for: Reference, do: def typeof(_), do: "Reference"
defimpl Typeable, for: Tuple, do: def typeof(_), do: "Tuple"

IO.puts Typeable.typeof "Hi"
IO.puts Typeable.typeof :ok

실제로 "유형"검사기를 원한다면 철학자의 석재 조직의 도구를 사용하여 쉽게 검사기를 작성할 수 있습니다. github.com/philosophers-stone . Phenetic은 아직 초기 단계이지만이 작업과 더 많은 작업을 수행 할 수 있습니다.
Fred the Magic Wonder Dog

쉽게 외부 의존에 묶여 있습니까? 어떻게하면 친구들과 코드를 공유 할 수 있습니까? 이것은 두 가지 문제로가는 길입니다.
Dmitry

편집 @aks 감사합니다; 나는 실제로 지금 4 칸으로 돌아갈 수있다 ^ _ ^
Dmitry

15

https://elixirforum.com/t/just-created-a-typeof-module/2583/5 의 코드를 붙여 넣습니다. :)

defmodule Util do
  types = ~w[function nil integer binary bitstring list map float atom tuple pid port reference]
  for type <- types do
    def typeof(x) when unquote(:"is_#{type}")(x), do: unquote(type)
  end
end

인용의 영리한 사용! 엘릭서 코드가 많을수록 펄을 생각 나게한다. ~ w 구성은 qw //와 매우 유사합니다. Perl에 Lisplike 견적을 시뮬레이션하는 영리한 메커니즘이 있는지 궁금합니다.
Dmitry

견적이 어떻게 작동하는지 궁금합니다. 정규식 프리 프로세서를 사용하여 에뮬레이션하거나 매크로 확장을 수행하기 위해 전체 코드를 파서가 필요로합니다.
Dmitry

1

매개 변수가 특정 유형이어야하는지 확인 해야하는 상황이 발생했습니다. 아마도 더 나은 방법으로 활동할 수 있습니다.

이처럼 :

@required [{"body", "binary"},{"fee", "integer"}, ...]
defp match_desire?({value, type}) do
  apply(Kernel, :"is_#{type}", [value])
end

용법:

Enum.map(@required, &(match_desire?/1))

1

아무도 언급하지 않았기 때문에

IO.inspect/1

객체를 콘솔로 출력합니다 ... JSON과 거의 같습니다.

당신의 인생을 테스트 할 때 물체가 어떻게 보이는지 알아낼 수 없을 때 매우 유용합니다.


4
질문에 대한 답변이 아니고 가까운 것도 아닙니다
LowFieldTheory
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.