Yeni başlayanlar hakkında uyarılması gereken Ruby Gotcha'lar nelerdir? [kapalı]


108

Yakın zamanda Ruby programlama dilini öğrendim ve sonuçta bu iyi bir dil. Ama beklediğim kadar basit olmadığını görünce oldukça şaşırdım. Daha doğrusu, "en az sürpriz kuralı" bana pek saygı duyulmadı (elbette bu oldukça özneldir). Örneğin:

x = true and false
puts x  # displays true!

ve ünlü:

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

Bir Ruby acemi hakkında uyaracağınız diğer "Gotchalar" nelerdir?


@ phrases.insert (0, p) Tamam @ phrases.insert (p) HİÇBİR ŞEY OLMAZ @phrases << p # TAMAM
Anno2001

neden true and falsedoğru dönüyor?
Jürgen Paul

3
Çünkü "x = doğru ve yanlış" aslında "(x = doğru) ve yanlış" olarak yorumlanıyor. Bu bir operatör önceliği meselesidir: "ve", "=" den daha düşük önceliğe sahiptir. Diğer dillerin çoğu ters önceliğe sahiptir, neden Rails'de bu sırayı seçtiklerini bilmiyorum, bunu çok kafa karıştırıcı buluyorum. "Normal" davranışı istiyorsanız, "x = (doğru ve yanlış)" yazmanız yeterlidir, bu durumda x yanlış olacaktır.
MiniQuark

4
Diğer bir çözüm ise "&&" ve "||" kullanmaktır. "ve" ve "veya" yerine: beklendiği gibi davranırlar. Örneğin: "x = true && false", x'in yanlış olmasına neden olur.
MiniQuark

“En sürpriz ilkesi azından ilkesi demektir benim için sürpriz.” from en.wikipedia.org/wiki/Ruby_(programming_language)#Philosophy Aynı şey Python için de geçerli. Python'un yaratıcısı hakkında benzer bir alıntı yaptım ama nerede olduğunu unuttum.
Darek Nędza

Yanıtlar:


59

Wikipedia Ruby gotchas

Makaleden:

  • Büyük harfle başlayan isimler sabit olarak kabul edilir, bu nedenle yerel değişkenler küçük harfle başlamalıdır.
  • Karakterler $ve @Perl'deki gibi değişken veri türünü göstermezler, ancak kapsam çözümleme operatörleri olarak işlev görürler.
  • Kayan nokta sayılarını belirtmek için, bir sıfır basamağı ( 99.0) veya açık bir dönüşüm ( 99.to_f) ile takip edilmelidir . 99.Sayılar yöntem sözdizimine duyarlı olduğundan bir nokta ( ) eklemek yetersizdir .
  • Olmayan boolean veri Boole değerlendirme katıdır: 0, ""ve []tüm değerlendirilir true. C'de ifade 0 ? 1 : 0, 0(yani yanlış) olarak değerlendirilir . Ruby'de, ancak, 1tüm sayıların değerlendirilmesiyle sonuçlanır true; sadece nilve falsedeğerlendir false. Bu kuralın doğal bir sonucu, Ruby yöntemlerinin geleneksel olarak - örneğin, düzenli ifade aramaları - başarı durumunda, ancak nilbaşarısızlık durumunda (örneğin, uyumsuzluk) sayıları, dizeleri, listeleri veya diğer yanlış olmayan değerleri döndürmesidir . Bu kural aynı zamanda, yalnızca özel nesnelerin olduğu trueve falseboole ifadesinde kullanılabildiği Smalltalk'ta da kullanılır .
  • 1.9'dan önceki sürümlerde bir karakter veri türü yoktur (karakterler için tür sağlayan C ile karşılaştırın char). Bu, dizeleri dilimlerken sürprizlere neden olabilir: "abc"[0]verim 97(dizedeki ilk karakterin ASCII kodunu temsil eden bir tam sayı); "a"kullanım elde etmek için "abc"[0,1](1 uzunluğunda bir alt dize) veya "abc"[0].chr.
  • Gösterim statement until expression, diğer dillerin eşdeğer ifadelerinin aksine (örneğin do { statement } while (not(expression));C / C ++ / ...), ifade zaten ise, aslında ifadeyi asla çalıştırmaz true. Bunun nedeni statement until expressionaslında sözdizimsel şekerin

    until expression
      statement
    end

    , bunun C / C ++ 'daki eşdeğeri while (not(expression)) statement;aynen statement if expressionşuna eşdeğerdir:

    if expression
      statement
    end

    Ancak, gösterim

    begin
      statement
    end until expression

    Ruby'de, ifade zaten doğru olsa bile, aslında ifadeyi bir kez çalıştıracaktır.

  • Sabitler nesnelere referans olduğundan, sabitin neyi ifade ettiğini değiştirmek bir uyarı oluşturur, ancak nesnenin kendisini değiştirmek bir uyarı oluşturmaz. Örneğin, Greeting << " world!" if Greeting == "Hello"bir hata veya uyarı oluşturmaz. Bu finalJava'daki değişkenlere benzer , ancak Ruby ayrıca Java'nın aksine bir nesneyi "dondurma" işlevine de sahiptir.

Diğer dillerden önemli ölçüde farklı olan bazı özellikler:

  • Her zamanki koşullu ifadeleri operatörleri, andve or, öncelik Normal kurallara uymaz: anddaha değil bağlamak sıkı yapar or. Yakut da ifade operatörler vardır ||ve &&beklendiği gibi çalışmasını.

  • defiçerisi defbir Python programcısının bekleyebileceğini yapmaz:

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

    Bu, xtanımlanmama konusunda bir hata verir . Kullanmanız gereken bir Proc.

Dil özellikleri

  • Yöntem bağımsız değişkenlerinin etrafında parantezlerin atlanması, yöntemler birden çok parametre alırsa beklenmedik sonuçlara yol açabilir. Ruby geliştiricileri, çok parametreli yöntemlerde parantezlerin çıkarılmasının gelecekteki Ruby sürümlerinde yasaklanabileceğini belirtmişlerdir; şimdiki (Kasım 2007) Ruby yorumlayıcısı (), kodun belirsiz anlamından kaçınmak için yazarı ihmal etmemeye teşvik eden bir uyarı atar . Kullanmama ()hala yaygın bir uygulamadır ve Ruby'yi, adı verilen yöntemin yanı sıra, kendisi tarafından okunabilir alana özgü bir programlama dili olarak kullanmak özellikle güzel olabilir method_missing().

1
Ruby 1.9 da karakter veri türünden yoksundur. 1.8'de, dizin operatörü bir Fixnum döndürdü; 1.9'da, tek karakterlik bir dizeyi dilimlemeye eşdeğerdir.
whitequark

38

Yeni başlayanlar eşitlik yöntemleriyle sorun yaşayacak :

  • a == b : a ve b'nin eşit olup olmadığını kontrol eder. Bu en kullanışlı olanıdır.
  • a.eql? b : ayrıca a ve b'nin eşit olup olmadığını kontrol eder, ancak bazen daha katıdır (örneğin, a ve b'nin aynı türe sahip olup olmadığını kontrol edebilir). Esas olarak Hash'larda kullanılır.
  • a.equal? b : a ve b'nin aynı nesne olup olmadığını kontrol eder (kimlik kontrolü).
  • a === b : durum ifadelerinde kullanılır (" a, b ile eşleşir " olarak okudum ).

Bu örnekler ilk 3 yöntemi netleştirmelidir:

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

Not olduğunu == , EQL? ve eşit mi? her zaman simetrik olmalıdır: eğer a == b ise b == a.

Ayrıca == ve eql? her ikisi de eşit olarak takma adlar olarak Object sınıfında uygulanır ? , yani yeni bir sınıf oluşturur ve == ve eql? düz kimlikten başka bir şey ifade etmek için ikisini de geçersiz kılmanız gerekir. Örneğin:

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

=== farklı yöntem davranır. Öncelikle o hepsinden değil simetrik (a === b gelmez değil o b === bir ima). Dediğim gibi, a === b'yi "a ile eşleşir b" olarak okuyabilirsiniz. İşte birkaç örnek:

# === 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)

Vaka bildirimi dayanmaktadır === yöntemiyle:

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

şuna eşdeğerdir:

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

Örnekleri bir çeşit kapsayıcı veya aralığı temsil eden yeni bir sınıf tanımlarsanız ( include? Veya match? Yöntemi gibi bir şey varsa ), o zaman === yöntemini şu şekilde geçersiz kılmayı yararlı bulabilirsiniz :

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

1
Ayrıca: a = 'строка'; b = 'строка'; pa == b; a = a.force_encoding 'ASCII-8BIT'; b = b.force_encoding 'UTF-8'; pa == b; pa === b; p a.eql? b; p a. eşit mi? b
Nakilon


18

Aşağıdaki kod beni şaşırttı. Bunun tehlikeli bir sorun olduğunu düşünüyorum: hem karşılaşması kolay hem de hata ayıklaması zor.

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

Bu yazdırır:

1
2 is even
3
4 is even
5

Ama bloktan önce bir comment =şey eklersem ...

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

Sonra alırım:

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

Temel olarak, bir değişken yalnızca bir blok içinde tanımlandığında, bloğun sonunda yok edilir ve ardından nilher yinelemede sıfırlanır . Genelde beklediğiniz budur. Değişken Ancak bir blok önce tanımlandığı gibidir, daha sonra, dış değişken blok içinde kullanılır ve değeri yineleme ve bu nedenle arada kalıcıdır.

Bunun yerine şunu yazmak bir çözüm olabilir:

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

Sanırım pek çok insan (ben de dahil) " a = b if c" yerine " " yazmaya meyilli a = (c ? b : nil)çünkü daha okunabilir ama belli ki yan etkileri var.


4
Diğer kapsam değişkenini de (1..5) do | number; comment | ..... Buradan okuyun stackoverflow.com/questions/1654637/…
Özgür

6
Bu bana mantıklı geliyor. Bu kapsam diğer diller için tipiktir, sadece farklı olan sözdizimidir.
g.

Ancak, a = (b if c)üçlü olmadan istediğiniz efekti elde etmek için yazabilirsiniz . Bunun nedeni , falsey b if cise nil olarak değerlendirilmesidir c.
Cameron Martin

16

superBağımsız değişken olmadan çağrı yapıldığında , geçersiz kılınan yöntem aslında geçersiz kılma yöntemiyle aynı bağımsız değişkenlerle çağrılır.

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"

Aslında supertartışmasız aramak için söylemeniz gerekir super().


3
Eğer B#hellosahip name = 42önce super, o zaman "42 Merhaba" diyor.
Andrew Grimm

14

Bloklar ve yöntemler varsayılan olarak son satırın değerini döndürür. Ekleme putshata ayıklama amacıyla sonuna ifadeleri nahoş yan etkilere neden olabilir



11

Sınıf değişkenlerini, sınıf özelliklerini ve sınıf yöntemlerini anlamakta çok zorlandım. Bu kod bir acemiye yardımcı olabilir:

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

1
Evet, sınıf değişkenleri yanıltıcı olabilir. Bence çoğu deneyimli Rubyist, onlardan kaçınmanın akıllıca olduğunu söyler, çünkü genellikle onlarsız bir problemi çözmenin başka yolları vardır. Hatta bazı dil meraklıları, Ruby'nin sınıf değişkenlerinin bir dil seviyesinde kötü tasarlandığını bile söyleyebilir.
David J.

8

Öğrendiğim bir şey, || = operatörünü dikkatli kullanmaktı. ve boolelerle uğraşıyorsanız özel dikkat gösterin. Ben genellikle, diğer her şey başarısız olursa ve 'a' sıfır kalırsa, 'a'ya varsayılan bir değer vermek için tümünü yakala olarak a || = b kullandım. ama eğer a yanlış ve b doğruysa, o zaman a doğru olarak atanacaktır.


Sen kullanabilir a = b if a.nil?ya @a = b unless defined?(@a).
Andrew Grimm

8
  • Blokları anlamak gerçekten önemli, her yerde kullanılıyorlar.

  • Yöntem parametrelerinin etrafında parantezlere ihtiyacınız yoktur. Bunları kullanıp kullanmama size kalmış. Bazıları onları her zaman kullanmanız gerektiğini söylüyor .

  • İstisnai durum için yükseltme ve kurtarmayı kullanın, fırlatıp yakalamayın.

  • Kullanabilirsiniz, ;ancak bir satıra birden fazla şey koymak istemediğiniz sürece yapmanız gerekmez.


Ruby 1.8.6'nın ötesine geçmeyi planlamıyorsanız, parantezleri istediğiniz kadar göz ardı edin. Aksi takdirde, muhtemelen bunları kullanmanız daha iyi olur.
Mike Woodhouse

7

Örnek yöntemlerini ve sınıf yöntemlerini içeren karışımlarla ilgili sorun yaşadım . Bu kod bir acemiye yardımcı olabilir:

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

İlk başta, ben hem örnek yöntemleri ile modüllere sahip düşündüm ve basitçe bunu yaparak sınıf yöntemleri:

module Displayable
  def display
    puts name
    self.class.increment_displays
  end
  def self.number_of_displays  # WRONG!
    @number_of_displays
  end
  [...]
end

Ne yazık ki, yöntem number_of_displays dahil ya da bir "modül sınıf yöntemi" olduğu için uzatılabilir asla. Yalnızca "modül örnek yöntemleri" bir sınıfa dahil edilebilir (örnek yöntemler olarak) veya bir sınıfa genişletilebilir (sınıf yöntemleri olarak). Bu nedenle, karışımınızın örnek yöntemlerini bir modüle ve karışımınızın sınıf yöntemlerini başka bir modüle yerleştirmeniz gerekir (genellikle sınıf yöntemlerini bir "ClassMethods" alt modülüne koyarsınız). Sayesinde dahil (örneğin yukarıda gösterildiği gibi) sihirli yöntemle, bunun kolay sadece bir basit hem örnek yöntemleri ve sınıf yöntemlerini içerecek şekilde yapabilirsiniz çağrısı "Görüntülenebilir include".

Bu mixin, her ekranı sınıf bazında sayacaktır . Sayaç bir sınıf özniteliğidir, bu nedenle her sınıfın kendine ait olacaktır (Person sınıfından yeni bir sınıf türeterseniz , türetilen sınıf için @ sayı_sayısı sayacı hiçbir zaman başlatılmayacağından programınız büyük olasılıkla başarısız olacaktır). Sen değiştirmek isteyebilir @number_of_displays tarafından @@ number_of_displays küresel bir sayaç yapmak. Bu durumda, her sınıf hiyerarşisinin kendi sayacı olacaktır. Global ve benzersiz bir sayaç istiyorsanız, muhtemelen bunu bir modül özelliği yapmalısınız.

Ruby ile başladığımda bunların tümü benim için kesinlikle sezgisel değildi.

Yine de bu mixin yöntemlerinden bazılarını nasıl temiz bir şekilde özel veya korumalı hale getireceğimi bulamıyorum (yalnızca display ve number_of_displays yöntemi genel yöntemler olarak dahil edilmelidir).


7

Aralık gösterimine dikkat edin.

(En azından, daha fazla dikkat ı başlangıçta yaptı!)

0..10 (İki nokta) ve 0...10(üç nokta) arasında bir fark vardır .

Ruby'den çok hoşlanıyorum. Ama nokta-nokta-nokta-nokta arasındaki bu nokta beni rahatsız ediyor. Bence bu kadar ince bir ikili sözdizimi "özelliği":

  • yanlış yazılması kolay ve
  • koda göz atarken gözlerinizle kolayca gözden kaçabilir

programlarımda tek tek yıkıcı hatalara neden olmamalı.


1
Çok farklı değildirler for (i=0; i<max; i++)vefor (i=0; i<=max; i++)
g.

0..10 ile 0 ... 10 arasındaki farkın ne olduğunu bulmaya çalışıyorum.
Luis D Urraca

6

Bence " and" ve " or" Ruby'nin daha bariz "ebeveynlerinden" biri olan Perl'e selam veriyor (en öne çıkan diğeri Smalltalk'tır). Her ikisi de çok daha düşük önceliğe (not davranış nereden geldiğini olan, aslında, atama daha düşük) sahip &&ve ||hangi kullanıyor olmalıdır operatörler bulunmaktadır.

Dikkat edilmesi gereken diğer şeyler hemen belli değil:

Bu şekilde görünmesine rağmen, yöntemleri / işlevleri gerçekten çağırmazsınız. Bunun yerine, Smalltalk'ta olduğu gibi, bir nesneye bir mesaj gönderirsiniz. Yani method_missinggerçekten daha çokmessage_not_understood .

some_object.do_something(args)

eşdeğerdir

some_object.send(:do_something, args) # note the :

Semboller çok yaygın olarak kullanılmaktadır. Bunlar, başlangıçta olan şeylerdir :ve hemen belli olmazlar (benim için öyle değildi) ama onlarla ne kadar erken başa çıkarsanız o kadar iyi olur.

Ruby, "ördek gibi yürürse ve ördek gibi şarlatan olursa ..." prensibini izleyerek "ördek yazımı" konusunda büyüktür.


Teşekkürler. Gönderme yöntemiyle ilgili nefret ettiğim bir şey var : sınıfın dışında bile özel yöntemleri çağırmanıza izin veriyor! Ahh.
MiniQuark

1
@MiniQuark: Gönderme yöntemini sevdiğim şey bu!
Andrew Grimm

6

attr_writerVeya attr_accessor(veya def foo=) kullanarak bir ayarlayıcı (aka mutatör) bildirirseniz, sınıfın içinden çağırırken dikkatli olun. Değişkenler örtük olarak bildirildiğinden, yorumlayıcının foo = baryöntemi çağırmak yerine her zaman foo adında yeni bir değişken bildirerek çözümlemesi gerekir 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

Bu aynı zamanda, veritabanındaki alanlara göre tanımlanan erişimcileri alan Rails ActiveRecord nesneleri için de geçerlidir. @-Style değişkenleri bile olmadıklarından, bu değerleri ayrı ayrı ayarlamanın uygun yolu self.value = 123veya ile self['value'] = 123.


5

Time ve Date sınıfı arasındaki farkı anlama. Her ikisi de farklıdır ve raylarda kullanırken sorunlar yaratmıştır. Time sınıfı bazen standart ruby ​​/ rails kitaplığında bulunan diğer Time sınıfı kitaplıklarıyla çakışır. Raylar uygulamamda tam olarak neler olup bittiğini anlamak kişisel olarak çok zamanımı aldı. Daha sonra ne zaman yaptığımı anladım

Time.new

Farkında bile olmadığım bir yerdeki bir kütüphaneden bahsediyordu.

Tam olarak ne söylemek istediğim konusunda net değilsem özür dilerim. Başkaları da benzer sorunlarla karşılaştıysa, lütfen yeniden açıklayın.


4

Beni geçmişte yakaladığım şey, \ndiğerlerinin yanı sıra satırsonu karakteri ( ) kaçış dizisinin tek tırnak içindeki dizelerle desteklenmemesidir. Ters eğik çizginin kendisi kaçar. Kaçmanın beklendiği gibi çalışması için çift tırnak kullanmanız gerekir.


1
Ve bu diğer dilden farklı mı?
Robert Gamble

Öncelikle Java. Java'da tek tırnak işaretleri yalnızca tek bir karakteri kapsamak için kullanılabilir, Dizeleri değil.
John Topley

1
Bu, dizeler için tek tırnak kullanmanıza izin veren herhangi bir dile uygundur ve bu yüzden yaparlar.
singpolyma

@John: doğru, ancak Java'da '\ n' yine de satırsonu karakteri olacak.
Jorn

1
Ancak Java'da tek tırnaklar yalnızca char türünde değerler oluşturur. Dizeler değil. Aradaki fark bu.
jmucchiello

4
x = (true and false) # x is false

Sizin de belirttiğiniz gibi 0 ve '' doğrudur.

Aynı ada sahip bir yönteme ve bir modül / sınıfa sahip olabilirsiniz (bu mantıklıdır, çünkü yöntem aslında Object'e eklenir ve dolayısıyla kendi ad alanına sahiptir).

Birden fazla kalıtım yoktur, ancak birden çok sınıfa ortak yöntemler eklemek için sıklıkla "mixin modülleri" kullanılır.


0 == doğru // beynimdeki c derleyicisi patlıyor !!
kenny

1
0 == true Ruby'de false verir. 0'ın doğru olması mantıklıdır çünkü doğru Ruby'de bir nesnedir. C 0'da sadece yanlış ile aynı temsile sahip olur.
Jules

Ruby'deki bir durumda, yalnızca falseve nilyanlıştır. Diğerleri gerçek değerlerdir.
rubyprince

4

Yöntemler yeniden tanımlanabilir ve sebebini keşfedene kadar akıl karıştırıcı olabilir. ( Kuşkusuz, bu hata bir Ruby on Rails denetleyicisinin eylemi yanlışlıkla yeniden tanımlandığında algılanması biraz "daha zordur"! )

#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

Çalıştırmak:

$ ruby demo.rb
=> "Hello from second definition"

Ancak, uyarılar etkin olarak arayın ve nedenini görebilirsiniz:

$ ruby -w demo.rb
demo.rb:10: warning: method redefined; discarding old hello1
=> "Hello from second definition"

Yapabilseydim uyarı kullanımında +100 tane olurdu.
Andrew Grimm

3

Bence her şeyde .length kullanmak her zaman iyidir ... boyut hemen hemen her şey tarafından desteklendiğinden ve Ruby dinamik türlere sahip olduğundan, yanlış türe sahip olduğunuzda .size şeklinde gerçekten garip sonuçlar alabilirsiniz ... a NoMethodError: undefined method `length ', bu yüzden Ruby'deki nesnelerde genellikle boyut çağırmam.

beni birden fazla ısırdı.

Ayrıca nesnelerin kimlikleri olduğunu unutmayın, bu yüzden sadece karışıklığı önlemek için id veya object_id çağrısı değişkenlerini kullanmamaya çalışıyorum. Bir Users nesnesinde bir id'ye ihtiyacım olursa, bunu user_id gibi bir adla adlandırmak en iyisidir.

Sadece iki sentim


2

Ruby'de yeniyim ve ilk turumda floats / string'leri bir tam sayıya çevirmekle ilgili bir sorunla karşılaştım. Float'larla başladım ve her şeyi f.to_int olarak kodladım . Ama devam ettiğimde ve dizeler için aynı yöntemi kullandığımda, programı çalıştırmaya geldiğinde bir eğri atıldım.

Görünüşe göre bir dizenin to_int yöntemi yoktur, ancak yüzer ve ints vardır.

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>

Keyfi parantezler beni de ilk başta attı. Bazı kodları olan ve olmayanlar gördüm. Her iki tarzın da kabul edildiğini anlamam biraz zaman aldı.


2

Monkut'un yanıtıyla ilgili olarak, Ruby's to_foo yöntemleri ne kadar katı bir dönüşüm gerçekleştireceklerine dair ipuçları veriyor.

Kısa olanlar to_i, to_stembel olmasını söyler ve bu formatta doğru bir şekilde temsil edilemese bile onları hedef türe dönüştürür. Örneğin:

"10".to_i == 10
:foo.to_s == "foo"

Artık açık fonksiyonlar gibi to_int, to_snesne doğal verilerin bu tür olarak temsil edilebileceğini ortalama. Örneğin, Rationalsınıf tüm rasyonel sayıları temsil eder, bu nedenle çağrı yapılarak doğrudan Fixnum (veya Bignum) tamsayı olarak temsil edilebilir to_int.

Rational(20,4).to_int == 5

Daha uzun yöntemi çağıramazsanız, bu, nesnenin o türde yerel olarak temsil edilemeyeceği anlamına gelir.

Temel olarak, dönüştürme yaparken, yöntem adlarında tembelseniz, Ruby dönüştürme konusunda tembel olacaktır.


1
Burada "tembel" doğru kelime mi?
Andrew Grimm



0

Bu beni bir kez kızdırdı:

1/2 == 0.5 #=> false
1/2 == 0   #=> true

Bunun Java, C ve C ++ 'da tamamen aynı şekilde davranacağına inanıyorum.
Larry

Bu komik, bunu düşünmedim bile, ama irb'yi açıp bunu denerseniz, mantıklı geliyor: Yani (1/2) bir Fixnum ve (0.5) bir Float. Ve Fixnim! = Float olduğunu biliyoruz.
DemitryT

2
@DemitryT Bence daha basit neden, türüne bakılmaksızın eşit olmayan bir şekilde 1/2değerlendirilmesidir . Ancak, ve . 00.5Rational(1, 2) == 0.51.0 == 1
Max Nanasy

evrensel dil hıçkırık burada. bu Ruby VE programlama konusunda yeni birinin bilmesi gereken bir şeydir.
dtc

0
1..5.each {|x| puts x}

çalışmıyor. Aralığı parantez içine koymalısınız, örneğin

(1..5).each {|x| puts x}

bu yüzden aradığınızı düşünmüyor 5.each. Sanırım bu, tıpkı x = true and falseGotcha gibi bir öncelik meselesi .


Ben buna parantez diyebilirim. İkinci olarak, herhangi bir kod bir dönüş değeri / öncelik sorunu gibi görünüyorsa, yine de parantez içine alınmalıdır. Yani, bana göre, bu "yakalamanın" özel bir yanı yok. Her kombinasyonel "gotcha" yazmaya devam edebilirsiniz, bu zaman kaybı olur. Açıkçası dostum, bu konuda beklenen sonucu alsanız bile, yine de parantez içine almayı tercih ederim.
Özgür
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.