23.md 4.0 KB
Newer Older
W
init  
wizardforcel 已提交
1 2 3 4
## 14.结构和 OpenStruct

好的,在前面的章节中,我们介绍了类,现在让我们简单地看一下名为 struct <sup class="footnote">[ [35](#_footnotedef_35 "View footnote.") ]</sup> 的简单事物。 输入以下程序并执行

W
wizardforcel 已提交
5
```rb
W
init  
wizardforcel 已提交
6 7 8 9 10 11 12 13 14 15 16 17
# struct_start.rb

person = Struct.new :name, :age
p = person.new
p.name = "Karthik"
p.age = 30

puts "Hello, I am #{p.name}, age #{p.age}"
```

输出量

W
wizardforcel 已提交
18
```rb
W
init  
wizardforcel 已提交
19 20 21
Hello, I am Karthik, age 30
```

W
wizardforcel 已提交
22
好了,现在让我们看看它是如何工作的。 首先,你将使用此语句创建新的`Struct`类型
W
init  
wizardforcel 已提交
23

W
wizardforcel 已提交
24
```rb
W
init  
wizardforcel 已提交
25 26 27
Struct.new :name, :age
```

W
wizardforcel 已提交
28
现在,你要命名它,以便可以使用它,将其命名为`person`
W
init  
wizardforcel 已提交
29

W
wizardforcel 已提交
30
```rb
W
init  
wizardforcel 已提交
31 32 33
person = Struct.new :name, :age
```

W
wizardforcel 已提交
34
命名后,此变量`person`的作用类似于`class`,你可以像这样声明它的新实例
W
init  
wizardforcel 已提交
35

W
wizardforcel 已提交
36
```rb
W
init  
wizardforcel 已提交
37 38 39 40 41 42 43
p = person.new
```

在上面的语句中,`p`是 person 的实例。

现在我们可以使用以下语句分配`p``:name``:age`

W
wizardforcel 已提交
44
```rb
W
init  
wizardforcel 已提交
45 46 47 48
p.name = "Karthik"
p.age = 30
```

W
wizardforcel 已提交
49
然后你可以打印数据,如下所示
W
init  
wizardforcel 已提交
50

W
wizardforcel 已提交
51
```rb
W
init  
wizardforcel 已提交
52 53 54
puts "Hello, I am #{p.name}, age #{p.age}"
```

W
wizardforcel 已提交
55
而已。 在不使用`class`的情况下,你创建了一个数据结构并使用了它! 你不觉得它很棒吗?
W
init  
wizardforcel 已提交
56 57 58

并不是`person = Struct.new :name, :age`中的`person`应该是可变的(即以小写字母开头),但是它也可以像`Person`一样是常量。 这就是这里的下一段代码中的确切内容

W
wizardforcel 已提交
59
```rb
W
init  
wizardforcel 已提交
60 61 62 63 64 65 66 67 68 69 70 71
# struct_constant.rb

Person = Struct.new :name, :age
p = Person.new
p.name = "Karthik"
p.age = 30

puts "Hello, I am #{p.name}, age #{p.age}"
```

Output

W
wizardforcel 已提交
72
```rb
W
init  
wizardforcel 已提交
73 74 75 76 77
Hello, I am Karthik, age 30
```

所以在这些行中

W
wizardforcel 已提交
78
```rb
W
init  
wizardforcel 已提交
79 80 81 82 83 84
Person = Struct.new :name, :age
p = Person.new
```

我们已经将`Person`与大写字母 P 结合使用,并且代码有效!

W
wizardforcel 已提交
85
如果你担心在上一个程序中需要输入很多字符,可以如下所示将其缩短。 请看下面的代码。
W
init  
wizardforcel 已提交
86

W
wizardforcel 已提交
87
```rb
W
init  
wizardforcel 已提交
88 89 90 91 92 93 94 95 96 97
# struct_one_line.rb

person = Struct.new :name, :age
p = person.new "Karthik", 30

puts "Hello, I am #{p.name}, age #{p.age}"
```

Output

W
wizardforcel 已提交
98
```rb
W
init  
wizardforcel 已提交
99 100 101 102 103
Hello, I am Karthik, age 30
```

我们得到相同的输出,但是在这一行中

W
wizardforcel 已提交
104
```rb
W
init  
wizardforcel 已提交
105 106 107 108 109
p = person.new "Karthik", 30
```

我们设法消除了这两条线

W
wizardforcel 已提交
110
```rb
W
init  
wizardforcel 已提交
111 112 113 114
p.name = "Karthik"
p.age = 30
```

W
wizardforcel 已提交
115
如果你注意到正确的话,`p = person.new "Karthik", 30`看起来不是类中的构造函数吗?
W
init  
wizardforcel 已提交
116

W
wizardforcel 已提交
117
并非`Struct`仅限于其属性数据结构。 你可以具有一个`Struct`实例可以调用的功能,如下面的程序所示。 输入并执行。
W
init  
wizardforcel 已提交
118

W
wizardforcel 已提交
119
```rb
W
init  
wizardforcel 已提交
120 121 122 123 124
include:code/struct_about_me.rb[]
```

Output

W
wizardforcel 已提交
125
```rb
W
init  
wizardforcel 已提交
126 127 128
Hello, I am Karthik, age 30
```

W
wizardforcel 已提交
129
如你所见,在 Struct 的`do end`块之间定义了一个名为`about_me`的函数。 我们在此行`p = person.new "Karthik", 30`中声明一个人`p`,然后像`puts p.about_me`这样调用`p`上的`about_me`函数,程序运行正常。 你还必须注意,我们可以将参数传递给 struct 中的函数,但是由于我的懒惰,我没有显示该示例。
W
init  
wizardforcel 已提交
130 131 132

现在让我们看看如何以错误的方式进行结构化。 在下面输入程序并执行

W
wizardforcel 已提交
133
```rb
W
init  
wizardforcel 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146
# struct_wrong.rb

person = Struct.new :name, :age
p = person.new
p.name = "Karthik"
p.age = 30
p.profession = "Engineer"

puts "Hello, I am #{p.name}, age #{p.age}, and I am on a #{p.profession}"
```

Output

W
wizardforcel 已提交
147
```rb
W
init  
wizardforcel 已提交
148 149 150
struct_wrong.rb:7:in `<main>': undefined method `profession=' for #<struct name="Karthik", age=30> (NoMethodError)
```

W
wizardforcel 已提交
151
如果你得到如上所示的输出,则表明你正确键入了该程序。 问题出在`p.profession = "Engineer"`行中,我们正在将数据分配给尚未在结构`person = Struct.new :name, :age`中声明的名为职业的属性。 因此会引发错误。 为了避免这些事情,你可以使用下面的程序中所示的 Open Struct
W
init  
wizardforcel 已提交
152

W
wizardforcel 已提交
153
```rb
W
init  
wizardforcel 已提交
154 155 156 157 158 159 160 161 162 163 164 165
# open_struct.rb

require 'ostruct'

p = OpenStruct.new
p.name = "Karthik"
p.age = 30
puts "Hello, I am #{p.name}, age #{p.age}"
```

Output

W
wizardforcel 已提交
166
```rb
W
init  
wizardforcel 已提交
167 168 169 170
Hello, I am Karthik, age 30
```

Open Struct 类似于 Struct,但是它没有预定义其数据结构或属性。