나는 최근에 Ruby 프로그래밍 언어를 배웠고 대체로 좋은 언어입니다. 하지만 제가 예상했던 것만 큼 간단하지 않다는 사실에 놀랐습니다. 더 정확하게는, “최소 놀라움의 법칙”은 나에게 그다지 존경스럽지 않은 것처럼 보였습니다 (물론 이것은 매우 주관적입니다). 예를 들면 :
x = true and false
puts x # displays true!
그리고 유명한 :
puts "zero is true!" if 0 # zero is true!
Ruby 초보자에게 경고 할 다른 “Gotchas”는 무엇입니까?
답변
기사에서 :
- 대문자로 시작하는 이름은 상수로 취급되므로 지역 변수는 소문자로 시작해야합니다.
$
및 문자@
는 Perl에서와 같이 가변 데이터 유형을 나타내지 않고 범위 분석 연산자로 기능합니다.- 부동 소수점 숫자를 표시하려면 0 자리 숫자 (
99.0
) 또는 명시 적 변환 (99.to_f
)을 따라야합니다 .99.
숫자는 메서드 구문에 영향을 받기 때문에 점 ( ) 을 추가하는 것만으로는 충분하지 않습니다 . - 비 부울 데이터의 부울 평가는 엄격 :
0
,""
그리고[]
모든 평가된다true
. C에서 표현식0 ? 1 : 0
은0
(즉, false)로 평가됩니다 . 그러나 Ruby에서는1
모든 숫자 가 다음 과 같이 평가되므로true
. 만nil
및false
평가합니다false
. 이 규칙의 결과는 규칙에 따라 Ruby 메서드 (예 : 정규 표현식 검색)가 성공시 숫자, 문자열, 목록 또는 기타 거짓이 아닌 값을 반환하지만nil
실패시 (예 : 불일치) 반환한다는 것 입니다. 이 규칙은 단지 특수 목적 스몰 토크에서 사용true
하고는false
부울 표현식에 사용할 수 있습니다. - 1.9 이전 버전에는 문자 데이터 유형이 없습니다 (문자 유형을 제공하는 C와 비교
char
). 이것은 문자열을 슬라이싱 할 때 놀라움을 유발할 수 있습니다."abc"[0]
yields97
( 문자열 의 첫 번째 문자의 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"
오류 또는 경고를 생성하지 않습니다. 이것은final
Java의 변수 와 유사 하지만 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의 메시지 기반 메소드 호출을 이용합니다. Rails 의 ActiveRecord 시스템은이를 사용하여 큰 효과를냅니다.
method_missing
send
답변
다음 코드는 저를 놀라게했습니다. 위험한 문제라고 생각합니다. 쉽게 실행할 수 있고 디버깅하기 어렵습니다.
(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
디버깅 목적으로 끝에 문을 추가 하면 불쾌한 부작용이 발생할 수 있습니다.
