[ruby] 초보자가주의해야 할 Ruby Gotchas는 무엇입니까? [닫은]

나는 최근에 Ruby 프로그래밍 언어를 배웠고 대체로 좋은 언어입니다. 하지만 제가 예상했던 것만 큼 간단하지 않다는 사실에 놀랐습니다. 더 정확하게는, “최소 놀라움의 법칙”은 나에게 그다지 존경스럽지 않은 것처럼 보였습니다 (물론 이것은 매우 주관적입니다). 예를 들면 :

x = true and false
puts x  # displays true!

그리고 유명한 :

puts "zero is true!" if 0  # zero is true!

Ruby 초보자에게 경고 할 다른 “Gotchas”는 무엇입니까?



답변

Wikipedia 루비 문제

기사에서 :

  • 대문자로 시작하는 이름은 상수로 취급되므로 지역 변수는 소문자로 시작해야합니다.
  • $및 문자 @는 Perl에서와 같이 가변 데이터 유형을 나타내지 않고 범위 분석 연산자로 기능합니다.
  • 부동 소수점 숫자를 표시하려면 0 자리 숫자 ( 99.0) 또는 명시 적 변환 ( 99.to_f)을 따라야합니다 . 99.숫자는 메서드 구문에 영향을 받기 때문에 점 ( ) 을 추가하는 것만으로는 충분하지 않습니다 .
  • 비 부울 데이터의 부울 평가는 엄격 : 0, ""그리고 []모든 평가된다 true. C에서 표현식 0 ? 1 : 00(즉, false)로 평가됩니다 . 그러나 Ruby에서는 1모든 숫자 가 다음 과 같이 평가되므로 true. 만 nilfalse평가합니다 false. 이 규칙의 결과는 규칙에 따라 Ruby 메서드 (예 : 정규 표현식 검색)가 성공시 숫자, 문자열, 목록 또는 기타 거짓이 아닌 값을 반환하지만 nil실패시 (예 : 불일치) 반환한다는 것 입니다. 이 규칙은 단지 특수 목적 스몰 토크에서 사용 true하고는 false부울 표현식에 사용할 수 있습니다.
  • 1.9 이전 버전에는 문자 데이터 유형이 없습니다 (문자 유형을 제공하는 C와 비교 char). 이것은 문자열을 슬라이싱 할 때 놀라움을 유발할 수 있습니다. "abc"[0]yields 97( 문자열 의 첫 번째 문자의 ASCII 코드를 나타내는 정수); 수득 "a"사용 "abc"[0,1]하거나 (1 길이의 문자열을) "abc"[0].chr.
  • 표기법 statement until expression은 다른 언어의 동등한 명령문 (예 : do { statement } while (not(expression));C / C ++ / …)과 달리 표현식이 이미이면 실제로 명령문을 실행하지 않습니다 true. 이것은 statement until expression실제로 구문 상 설탕 이기 때문 입니다.

    until expression
      statement
    end

    등가의 C에있는 / C ++이다 while (not(expression)) statement;처럼 statement if expression에 상당

    if expression
      statement
    end

    그러나 표기법

    begin
      statement
    end until expression

    루비에서는 표현식이 이미 참인 경우에도 실제로 한 번 문을 실행합니다.

  • 상수는 객체에 대한 참조이므로 상수가 참조하는 내용을 변경하면 경고가 생성되지만 객체 자체를 수정하면 그렇지 않습니다. 예를 들어 Greeting << " world!" if Greeting == "Hello"오류 또는 경고를 생성하지 않습니다. 이것은 finalJava의 변수 와 유사 하지만 Ruby에는 Java와 달리 객체를 “고정”하는 기능도 있습니다.

다른 언어와 현저하게 다른 일부 기능 :

  • 조건식 and및 의 일반적인 연산자 or는 일반적인 우선 순위 규칙을 따르지 and않습니다 or. 보다 엄격하게 바인딩하지 않습니다 . Ruby에는 표현식 연산자도 있습니다.||&&예상대로 작동합니다.

  • def 내부 def 는 파이썬 프로그래머가 기대하는 바를 수행하지 않습니다.

    def a_method
        x = 7
        def print_x; puts x end
        print_x
    end

    이것은 다음에 대한 오류를 제공합니다. x 정의되지 않은 것에 . 당신은을 사용해야합니다 Proc.

언어 기능

  • 메서드 인수 주위에 괄호를 생략하면 메서드가 여러 매개 변수를 사용하는 경우 예기치 않은 결과가 발생할 수 있습니다. Ruby 개발자는 향후 Ruby 버전에서 다중 매개 변수 메소드에서 괄호를 생략하는 것이 허용되지 않을 수 있다고 말했습니다. 현재 (2007 년 11 월) Ruby 인터프리터는 ()코드의 모호한 의미를 피하기 위해 작성자가를 생략하지 않도록 권장하는 경고를 표시 합니다. 사용하지 않는 ()것은 여전히 ​​일반적인 관행이며, 루비를라는 메소드와 함께 사람이 읽을 수있는 도메인 별 프로그래밍 언어 자체로 사용하는 것이 특히 좋습니다 method_missing().

답변

초보자는 평등 방법에 문제가 있습니다 .

  • a == b : a와 b가 같은지 확인합니다. 이것이 가장 유용합니다.
  • a.eql? b : 또한 a와 b가 같은지 확인하지만 때로는 더 엄격합니다 (예를 들어 a와 b가 동일한 유형인지 확인할 수 있음). 주로 해시에서 사용됩니다.
  • a. 같습니까? b : a와 b가 동일한 객체인지 확인 (신원 확인)
  • a === b : case 문에 사용됩니다 ( ” a matches b ” 로 읽음 ).

이 예제는 처음 세 가지 방법을 명확히해야합니다.

a = b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # true (a.object_id == b.object_id)

a = "joe"
b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # false (a.object_id != b.object_id)

a = 1
b = 1.0

a==b       # true
a.eql? b   # false (a.class != b.class)
a.equal? b # false

참고 == , EQL? 그리고 동등합니까? 항상 대칭이어야합니다. a == b이면 b == a입니다.

또한 ==eql? 둘 다 동일한 별칭으로 Object 클래스에서 구현 됩니까? , 그래서 새 클래스를 만들고 ==eql을 원한다면 ? 평범한 정체성이 아닌 다른 것을 의미하려면 둘 다 재정의해야합니다. 예를 들면 :

class Person
    attr_reader name
    def == (rhs)
      rhs.name == self.name  # compare person by their name
    end
    def eql? (rhs)
      self == rhs
    end
    # never override the equal? method!
end

=== 다른 방법 동작합니다. 우선 그것은 대칭 적이 지 않습니다 (a === b는 b === a를 의미 하지 않습니다 ). 내가 말했듯이 a === b를 “a가 b와 일치”로 읽을 수 있습니다. 다음은 몇 가지 예입니다.

# === is usually simply an alias for ==
"joe" === "joe"  # true
"joe" === "bob"  # false

# but ranges match any value they include
(1..10) === 5        # true
(1..10) === 19       # false
(1..10) === (1..10)  # false (the range does not include itself)

# arrays just match equal arrays, but they do not match included values!
[1,2,3] === [1,2,3] # true
[1,2,3] === 2       # false

# classes match their instances and instances of derived classes
String === "joe"   # true
String === 1.5     # false (1.5 is not a String)
String === String  # false (the String class is not itself a String)

경우 문을 기반으로 ===의 방법 :

case a
  when "joe": puts "1"
  when 1.0  : puts "2"
  when (1..10), (15..20): puts "3"
  else puts "4"
end

다음과 같습니다.

if "joe" === a
  puts "1"
elsif 1.0 === a
  puts "2"
elsif (1..10) === a || (15..20) === a
  puts "3"
else
  puts "4"
end

인스턴스가 일종의 컨테이너 또는 범위를 나타내는 새 클래스를 정의하는 경우 ( include? 또는 match? 메서드 같은 것이있는 경우 ) 다음 과 같이 === 메서드 를 재정의하는 것이 유용 할 수 있습니다 .

class Subnet
  [...]
  def include? (ip_address_or_subnet)
    [...]
  end
  def === (rhs)
    self.include? rhs
  end
end

case destination_ip
  when white_listed_subnet: puts "the ip belongs to the white-listed subnet"
  when black_listed_subnet: puts "the ip belongs to the black-listed subnet"
  [...]
end


답변

  • 원숭이 패치 . Ruby에는 개방형 클래스가 있으므로 런타임에 동작을 동적으로 변경할 수 있습니다.

  • 또는 재정의 된 경우 개체가 정의되지 않은 메서드에 응답 할 수 있습니다 . 이것은 Ruby의 메시지 기반 메소드 호출을 이용합니다. RailsActiveRecord 시스템은이를 사용하여 큰 효과를냅니다.method_missingsend


답변

다음 코드는 저를 놀라게했습니다. 위험한 문제라고 생각합니다. 쉽게 실행할 수 있고 디버깅하기 어렵습니다.

(1..5).each do |number|
  comment = " is even" if number%2==0
  puts number.to_s + comment.to_s
end

이것은 다음을 인쇄합니다.

1
2 is even
3
4 is even
5

하지만 블록 앞에 comment =아무것도 추가 하면 …

comment = nil
(1..5).each do |number|
  comment = " is even" if number%2==0
  puts number.to_s + comment.to_s
end

그런 다음 얻을 :

1
2 is even
3 is even
4 is even
5 is even

기본적으로 변수가 블록 내부에서만 정의되면 블록의 끝에서 소멸되고 nil매 반복마다 재설정됩니다 . 그것은 일반적으로 당신이 기대하는 것입니다. 그러나 변수 블록 이전에 정의 된 외부 변수가 블록 내부에서 사용되므로 그 값은 반복 사이에 지속됩니다.

한 가지 해결책은 다음과 같이 작성하는 것입니다.

comment = number%2==0 ? " is even" : nil

나는 (나를 포함하여) 많은 사람들이 ” a = b if c“대신 ” ” 를 쓰는 경향이 있다고 생각합니다 a = (c ? b : nil). 왜냐하면 더 읽기 쉬우 기 때문입니다. 그러나 분명히 부작용이 있습니다.


답변

super인수없이 호출 할 때 재정의 된 메서드는 실제로 재정의 메서드와 동일한 인수를 사용하여 호출됩니다.

class A
  def hello(name="Dan")
    puts "hello #{name}"
  end
end

class B < A
  def hello(name)
    super
  end
end

B.new.hello("Bob") #=> "hello Bob"

실제로 super인수없이 호출하려면 라고 말해야 super()합니다.


답변

블록과 메서드는 기본적으로 마지막 줄의 값을 반환합니다. puts디버깅 목적으로 끝에 문을 추가 하면 불쾌한 부작용이 발생할 수 있습니다.


답변