초보자가주의해야 할 Ruby Gotchas는 무엇입니까? [닫은]
저는 최근에 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
. 보다 엄격하게 바인딩하지 않습니다 . 루비는 표현식 연산자가||
및&&
예상대로 작동합니다.def
insidedef
는 파이썬 프로그래머가 기대하는 바를 수행하지 않습니다.def a_method x = 7 def print_x; puts x end print_x end
이것은
x
정의되지 않은 것에 대한 오류를 제공합니다 . 당신은을 사용해야합니다Proc
.
언어 기능
- 메서드 인수 주위에 괄호를 생략하면 메서드가 여러 매개 변수를 사용하는 경우 예기치 않은 결과가 발생할 수 있습니다. Ruby 개발자는 향후 Ruby 버전에서 다중 매개 변수 메소드에서 괄호를 생략하는 것이 허용되지 않을 수 있다고 말했습니다. 현재 (2007 년 11 월) Ruby 인터프리터는
()
코드의 모호한 의미를 피하기 위해 작성자가를 생략하지 않도록 권장하는 경고를 표시 합니다. 사용하지 않는()
것은 여전히 일반적인 관행이며, 특히 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에는 개방형 클래스가 있으므로 런타임에 동작을 동적으로 변경할 수 있습니다.
개체 수있는 정의되지 않은 방법에 응답 하는 경우
method_missing
또는send
무시되었습니다. 이것은 Ruby의 메시지 기반 메소드 호출을 이용합니다. Rails 의 ActiveRecord 시스템은이를 사용하여 큰 효과를냅니다.
다음 코드는 저를 놀라게했습니다. 위험한 문제라고 생각합니다. 쉽게 실행할 수 있고 디버깅하기 어렵습니다.
(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
디버깅 목적으로 끝에 문을 추가 하면 불쾌한 부작용이 발생할 수 있습니다.
상속은 Ruby에서 메서드 가시성 을 결정하는 데 아무런 역할을하지 않습니다 .
클래스 변수, 클래스 속성 및 클래스 메서드를 이해하는 데 많은 어려움이있었습니다. 이 코드는 초보자에게 도움이 될 수 있습니다.
class A
@@classvar = "A1"
@classattr = "A2"
def self.showvars
puts "@@classvar => "+@@classvar
puts "@classattr => "+@classattr
end
end
A.showvars
# displays:
# @@classvar => A1
# @classattr => A2
class B < A
@@classvar = "B1"
@classattr = "B2"
end
B.showvars
# displays:
# @@classvar => B1
# @classattr => B2
A.showvars
# displays:
# @@classvar => B1 #Class variables are shared in a class hierarchy!
# @classattr => A2 #Class attributes are not
내가 배운 한 가지는 연산자 || =를 조심스럽게 사용하는 것이었다. 부울을 다루는 경우 특별히주의하십시오. 다른 모든 것이 실패하고 'a'가 nil 인 경우 'a'에 기본값을 제공하기 위해 일반적으로 a || = b를 catch all로 사용했습니다. 그러나 a가 거짓이고 b가 참이면 a가 참으로 할당됩니다.
블록은 이해하는 데 정말 중요하며 모든 곳에서 사용됩니다.
메소드 매개 변수를 괄호로 묶지 않아도됩니다. 사용 여부는 귀하에게 달려 있습니다. 어떤 사람들은 항상 그것들을 사용해야한다고 말합니다 .
예외 처리를 위해 throw 및 catch가 아닌 raise 및 rescue를 사용하십시오.
사용할 수는
;
있지만 한 줄에 여러 항목을 넣고 싶지 않으면 사용할 필요가 없습니다.
인스턴스 메서드 와 클래스 메서드 를 포함하는 믹스 인에 문제가있었습니다 . 이 코드는 초보자에게 도움이 될 수 있습니다.
module Displayable
# instance methods here
def display
puts name
self.class.increment_displays
end
def self.included(base)
# This module method will be called automatically
# after this module is included in a class.
# We want to add the class methods to the class.
base.extend Displayable::ClassMethods
end
module ClassMethods
# class methods here
def number_of_displays
@number_of_displays # this is a class attribute
end
def increment_displays
@number_of_displays += 1
end
def init_displays
@number_of_displays = 0
end
# this module method will be called automatically
# after this module is extended by a class.
# We want to perform some initialization on a
# class attribute.
def self.extended(base)
base.init_displays
end
end
end
class Person
include Displayable
def name; @name; end
def initialize(name); @name=name; end
end
puts Person.number_of_displays # => 0
john = Person.new "John"
john.display # => John
puts Person.number_of_displays # => 1
jack = Person.new "Jack"
jack.display # => Jack
puts Person.number_of_displays # => 2
처음에는 간단하게 다음 과 같이 인스턴스 메서드 와 클래스 메서드 를 모두 포함하는 모듈을 가질 수 있다고 생각 했습니다.
module Displayable
def display
puts name
self.class.increment_displays
end
def self.number_of_displays # WRONG!
@number_of_displays
end
[...]
end
불행히도 number_of_displays 메소드 는 "모듈 클래스 메소드"이기 때문에 절대 포함되거나 확장되지 않습니다. "모듈 인스턴스 메서드"만 클래스에 포함되거나 (인스턴스 메서드로) 클래스로 확장 될 수 있습니다 (클래스 메서드로). 이것이 믹스 인의 인스턴스 메서드를 모듈에, 믹스 인의 클래스 메서드를 다른 모듈에 넣어야하는 이유입니다 (보통 클래스 메서드를 "ClassMethods"서브 모듈에 넣습니다). 포함 된 매직 메서드 덕분 에 단 하나의 간단한 "include Displayable"호출에 인스턴스 메서드와 클래스 메서드를 모두 쉽게 포함 할 수 있습니다 (위의 예 참조).
이 믹스 인은 각 디스플레이를 클래스 별로 계산합니다. 카운터는 클래스 속성이므로 각 클래스에는 고유 한 속성이 있습니다 (파생 클래스의 @number_of_displays 카운터가 초기화되지 않으므로 Person 클래스에서 새 클래스를 파생하면 프로그램이 실패 할 수 있음). @number_of_displays 를 @@ number_of_displays 로 대체 하여 글로벌 카운터로 만들 수 있습니다. 이 경우 각 클래스 계층에는 자체 카운터가 있습니다. 전역적이고 고유 한 카운터를 원한다면 모듈 속성으로 만들어야합니다.
이 모든 것이 Ruby로 시작했을 때 제게 직관적이지 않았습니다.
나는 여전히 이러한 mixin 메소드 중 일부를 비공개 또는 보호로 만드는 방법을 알 수 없습니다 ( display 및 number_of_displays 메소드 만 공개 메소드로 포함되어야 함).
범위 표기법에주의하십시오.
(적어도,보다 더 많은 관심을 지불 내가 처음에 한을!)
0..10
(2 개의 점)과 0...10
(3 개의 점) 사이에 차이가 있습니다 .
저는 Ruby를 아주 좋아합니다. 그러나이 점-점 대 점-점-점은 나를 괴롭힌다. 나는 다음과 같은 미묘한 이중 구문 "기능"이라고 생각합니다.
- 오타하기 쉽고
- 코드를 훑어 보면서 눈으로 쉽게 놓칠 수 있습니다.
내 프로그램에 치명적인 버그를 일으킬 수 없어야합니다.
I think "and
" and "or
" are nods to Perl, which is one of Ruby's more obvious "parents" (the most prominent other being Smalltalk). They both have much lower precedence (lower than assignment, in fact, which is where the behaviour noted comes from) than &&
and ||
which are the operators you should be using.
Other things to be aware of that aren't immediately obvious:
You don't really call methods/functions, although it kinda looks that way. Instead, as in Smalltalk, you send a message to an object. So method_missing
is really more like message_not_understood
.
some_object.do_something(args)
is equivalent to
some_object.send(:do_something, args) # note the :
Symbols are very widely used. That's those things that start with :
and they're not immediately obvious (well they weren't to me) but the earlier you get to grips with them the better.
Ruby is big on "duck-typing", following the principal that "if it walks like a duck and quacks like a duck..." that allows informal substitution of objects with a common subset of methods without any explicit inheritance or mixin relationship.
If you declare a setter (aka mutator) using attr_writer
or attr_accessor
(or def foo=
), be careful of calling it from inside the class. Since variables are implicitly declared, the interpreter always has to resolve foo = bar
as declaring a new variable named foo, rather than calling the method self.foo=(bar)
.
class Thing
attr_accessor :foo
def initialize
@foo = 1 # this sets @foo to 1
self.foo = 2 # this sets @foo to 2
foo = 3 # this does *not* set @foo
end
end
puts Thing.new.foo #=> 2
This also applies to Rails ActiveRecord objects, which get accessors defined based on fields in the database. Since they're not even @-style instance variables, the proper way to set those values individually is with self.value = 123
or self['value'] = 123
.
Understanding the difference between Time and Date class. Both are different and have created issues while using them in rails. The Time class sometimes conflicts with other Time class libraries present in standard ruby/rails library. It personally took me a lot of time to understand what was exactly going on in my rails app. Later, I figured when I did
Time.new
It was referring to some library in a location that I was not even aware of.
Sorry if I am not clear with what I want to say exactly. If others have faced similar problems, please re-explain.
One that's caught me out in the past is that the newline character (\n
) escape sequence—amongst others—isn't supported by strings within single quotes. The backslash itself gets escaped. You have to use double quotes for the escaping to work as expected.
x = (true and false) # x is false
0 and '' are true, as you pointed out.
You can have a method and a module/class by the same name (which makes sense, because the method actually gets added to Object and thus has its own namespace).
There is no multiple inheritance, but frequently "mixin modules" are used to add common methods to multiple classes.
Methods can be redefined and can become a mind-scratcher until you discover the cause. (Admittedly, this error is probably a bit "harder" to detect when a Ruby on Rails controller's action is re-defined by mistake!)
#demo.rb
class Demo
def hello1
p "Hello from first definition"
end
# ...lots of code here...
# and you forget that you have already defined hello1
def hello1
p "Hello from second definition"
end
end
Demo.new.hello1
Run:
$ ruby demo.rb
=> "Hello from second definition"
But call it with warnings enabled and you can see the reason:
$ ruby -w demo.rb
demo.rb:10: warning: method redefined; discarding old hello1
=> "Hello from second definition"
I think it is always good to use .length on things... since size is supported by nearly everything and Ruby has dynamic types you can get really weird results calling .size when you have the wrong type... I would much rather get a NoMethodError: undefined method `length', so I generally never call size on objects in Ruby.
bit me more than once.
Also remember objects have ids, so I try not to use variables call id or object_id just to avoid confusion. If I need an id on a Users object it is best to call it something like user_id.
Just my two cents
I'm new to ruby, and on my first round I hit an issue regarding changing floats/strings to an integer. I started with the floats and coded everything as f.to_int. But when I continued on and used the same method for strings I was thrown a curve when it came to run the program.
Aparently a string doesn't have a to_int method, but floats and ints do.
irb(main):003:0* str_val = '5.0'
=> "5.0"
irb(main):006:0> str_val.to_int
NoMethodError: undefined method `to_int' for "5.0":String
from (irb):6
irb(main):005:0* str_val.to_i
=> 5
irb(main):007:0> float_val = 5.0
=> 5.0
irb(main):008:0> float_val.to_int
=> 5
irb(main):009:0> float_val.to_i
=> 5
irb(main):010:0>
Arbitrary parenthesis threw me at first too. I saw some code with and some without. It took me awhile to realize that either styles are accepted.
Related to monkut's response, Ruby's to_foo
methods hint at how strict a conversion they'll do.
Short ones like to_i
, to_s
tell it to be lazy, and convert them to the target type even if they're not able to be represented accurately in that format. For example:
"10".to_i == 10
:foo.to_s == "foo"
The longer explicit functions like to_int
, to_s
mean that the object can be natively represented as that type of data. For example, the Rational
class represents all rational numbers, so it can be directly represented as a Fixnum (or Bignum) integer by calling to_int
.
Rational(20,4).to_int == 5
If you can't call the longer method, it means the object can't be natively represented in that type.
So basically, when converting, if you're lazy with the method names, Ruby will be lazy with the conversion.
From In Ruby why won't foo = true unless defined?(foo)
make the assignment?
foo = true unless defined?(foo) #Leaves foo as nil
Because foo
is defined as nil
when defined?(foo)
is called.
Iteration over ruby hashes aren't guaranteed to happen in any particular order. (It's not a bug, it's a feature)
Hash#sort
is useful if you need a particular order.
Related question: Why are Ruby’s array of 1000 hashes' key and value pairs always in a particular order?
This one made me mad once:
1/2 == 0.5 #=> false
1/2 == 0 #=> true
1..5.each {|x| puts x}
doesn't work. You have to put the range into parentheses, like
(1..5).each {|x| puts x}
so it doesn't think you're calling 5.each
. I think this is a precedence issue, just like the x = true and false
gotcha.
참고URL : https://stackoverflow.com/questions/372652/what-are-the-ruby-gotchas-a-newbie-should-be-warned-about
'Programing' 카테고리의 다른 글
mysql에서 순차 번호 매기기의 차이를 찾는 방법은 무엇입니까? (0) | 2020.08.09 |
---|---|
외부 라이브러리에 대한 CMake 링크 (0) | 2020.08.09 |
목록에 목록에있는 항목이있는 linq (0) | 2020.08.09 |
여러 양식 필드에 의존하는 Angular2 유효성 검사기 (0) | 2020.08.09 |
JavaScript를 사용하여 HTML의 CSS 배경색을 설정하는 방법 (0) | 2020.08.09 |