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.