使用字符串方法的方式有关系吗?

时间:2016-03-30 13:53:08

标签: ruby string immutability method-chaining

Codeacademy教导您可以将多种方法链接在一起:

user_input.method1.method2.method3

但是,在后面的课程中,他们会显示一些这样的方法:

user_input = gets.chomp
user_input.downcase!

我把它们结合起来:

user_input = gets.chomp.downcase!

当我以这种方式使用它时:

user_input = gets.chomp.downcase!
if user_input.include? "s"
...

我收到错误"undefined method `include?'"。如果我将其更改为以下内容,则可以正常工作:

user_input = gets.chomp
user_input.downcase!
if user_input.include? "s"
...

我很茫然。我担心这是否是他们的控制台的怪癖,或者这是我应该如何在Ruby中做到这一点。如果有人能告诉我哪种方式是正确的,我会很感激。如果两者都是对的,那也没关系。

4 个答案:

答案 0 :(得分:1)

首先,如果您还没有完全理解,可以通过=为变量赋值,并且可以通过将.class附加到任何内容来检查变量类型。

请考虑以下事项:

name = 'John'
puts name
# => John
puts name.class
# => String

现在,其次,应该注意ALL方法的返回值是完全不同的。但所有这些都可以分为两类:

方法:

  1. 返回自我
  2. 返回除自我以外的任何内容
  3. 1的示例

    - 返回self的方法,你可以说返回相同类型对象的方法,在我们的特定情况下,String

    name = 'John'
    puts name
    # => 'John'
    puts name.class
    # => String
    
    downcased_name = name.downcase
    puts downcased_name
    # => john
    puts downcased_name.class
    # => String
    
    deleted_downcased_name = downcased_name.delete('h')
    puts deleted_downcased_name
    # => jon
    puts deleted_downcased_name.class
    # => String
    
    # All of the above can be just simplified into:
    
    deleted_downcased_name2 = 'John'.downcase.delete('h')
    puts deleted_downcased_name2
    # => jon
    puts deleted_downcased_name2.class
    # => String
    

    请注意,deleted_downcased_namedeleted_downcased_name2是相同的,因为您可以将链接方法视为链接返回值“John” - > 'john' - > '乔恩'。

    2

    的示例

    - 返回除self之外的任何东西的方法,你可以说返回不同类型的方法。

    在我们的特定情况下,字符串的downcase!会返回StringNilClass (reference here)

    • 如果字符串更改,则返回String,或
    • 如果字符串已经下降开始(没有更改),则返回nil

    或其他字符串的方法:start_with? (reference here)

    • 返回truefalse

    当您尝试将String方法用作nil值的链时,这就是方法链接不起作用的地方(引发错误)。

    考虑以下

    name = 'mary' 
    puts name
    # => 'mary'
    puts name.class
    # => String
    
    downcased_name = name.downcase!
    puts downcased_name
    # => nil
    puts downcased_name.class
    # => NilClass
    
    downcased_name.delete('h')
    # => This will raise the following error
    # NoMethodError: undefined method `delete' for nil:NilClass
    

    上面的错误是因为downcased_name是NilClass的一种类型,您希望它是String的类型。因此,您不能再在其上链接任何字符串方法。您只能在String类型的值上链接String个方法。同样,您只能在Number类型的值上链接Number个方法。

    每当有疑问时,您都可以随时查看文档以检查方法的作用以及返回值和类型。

答案 1 :(得分:0)

您遇到的问题是使用爆炸方法downcase!

这基本上是说"改变原始字符串,使其为小写"。 重要的是返回nil。因此,您实际上是在include?上调用nil

如果您使用非爆炸方法downcase,它会说"对先前链接的东西进行倒置,但不要改变原始"。关键区别在于它返回的结果而不是nil

以下是一个例子:

str = "ABCD"
str.downcase!
=> nil

str
=> "abcd"

str = "ABCD"
str.downcase
=> "abcd"

str
=> "ABCD"  # Note str is still unchanged unless you set str = str.downcase 

答案 2 :(得分:0)

欢迎来到Ruby!虽然您在Codeacademy的学徒期可能有限,但您将在整个职业生涯中继续参考语言API文档。 API文档描述了语言(或库)为您所做的事情。在这种情况下,您正在使用downcase!,正如一位评论者指出的那样,它并不总是返回一个字符串。当它不采取任何行动时,它返回零。 Nil是Ruby中的一个对象(就像其他所有东西一样),但是'include?'没有为nil定义方法,这解释了你的错误。 (这是Ruby中最常见的错误之一,了解其含义。)

所以,事实上,这里打破的不是你的方法链。这是其中一个中间方法没有返回你期望的类型的值(nil而不是某种String)。

答案 3 :(得分:0)

链接非破坏性方法,如:

string.chomp.downcase...

的优点是代码简洁,但如果您对对象的原始状态不感兴趣,并且只想要最终结果,因为它在链中创建了中间对象,效率不高。

另一方面,将破坏性方法依次应用于同一对象:

string.chomp!
string.downcase!
...
如果你不需要保持对象的原始状态,那么

会更有效率,但是不简洁。

将可能返回不同类的对象(特别是nil)的方法组合为:

string = gets.chomp!.downcase!...

是错误的,因为结果可能会在链中的某个点变为nil

在您最后的位置应用可能的nil - 返回方法:

string = gets.chomp.downcase!
如果您希望string始终是一个字符串,

仍然无用,并且很容易导致错误。

如果你想在你的例子中链接这些方法,也许你可以这样做:

user_input = gets.tap(&:chomp!).tap(&:downcase!)
if user_input.include?("s")
...