我有一个Board
(a.k.a。&mut Vec<Vec<Cell>>
)我想在迭代时更新。我想要更新的新值来自一个函数,该函数需要&Vec<Vec<Cell>>
到我正在更新的集合。
我尝试了几件事:
使用board.iter_mut().enumerate()
和row.iter_mut().enumerate()
,以便我可以更新最里面的循环中的cell
。 Rust不允许调用next_gen
函数,因为它需要&Vec<Vec<Cell>>
,并且当你已经有一个可变引用时,你就不能有一个不可变引用。
更改next_gen
功能签名以接受&mut Vec<Vec<Cell>>
。 Rust不允许对对象进行多次可变引用。
我目前将所有更新推迟到HashMap
,然后在我执行迭代后应用它们:
fn step(board: &mut Board) {
let mut cells_to_update: HashMap<(usize, usize), Cell> = HashMap::new();
for (row_index, row) in board.iter().enumerate() {
for (column_index, cell) in row.iter().enumerate() {
let cell_next = next_gen((row_index, column_index), &board);
if *cell != cell_next {
cells_to_update.insert((row_index, column_index), cell_next);
}
}
}
println!("To Update: {:?}", cells_to_update);
for ((row_index, column_index), cell) in cells_to_update {
board[row_index][column_index] = cell;
}
}
有没有办法可以让代码更新board
&#34;就位&#34;,也就是说,在最里面的循环中,同时仍然可以在内部调用next_gen
最里面的循环?
免责声明:
我正在学习Rust,我知道这不是最好的方法。我一直在玩,看看我能做什么,不能做什么。我也试图限制任何复制以限制自己一点点。作为oli_obk - ker mentions, this implementation for Conway's Game of Life is flawed。
此代码旨在衡量一些事项:
根据我在评论中收集的内容,可以使用std::cell::Cell
。但是,使用std:cell:Cell
规避了一些核心Rust原则,我将其描述为我的困境&#34;在最初的问题中。
答案 0 :(得分:5)
有没有办法让这个代码“就地”更新电路板?
存在专门为这些情况制作的类型。它恰巧被称为std::cell::Cell
。你被允许改变class CompassWidget(QWidget):
angleChanged = pyqtSignal(float)
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self._angle = 0.0
self._margins = 10
self._pointText = {0: "N", 45: "NE", 90: "E", 135: "SE", 180: "S",
225: "SW", 270: "W", 315: "NW"}
self.animation = QPropertyAnimation(self, 'angle')
self.animation.setEasingCurve(QEasingCurve.InOutExpo)
self.animation.setDuration(1500)
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.fillRect(event.rect(), self.palette().brush(QPalette.Window))
self.drawMarkings(painter)
self.drawNeedle(painter)
painter.end()
def drawMarkings(self, painter):
painter.save()
painter.translate(self.width()/2, self.height()/2)
scale = min((self.width() - self._margins)/120.0,
(self.height() - self._margins)/120.0)
painter.scale(scale, scale)
font = QFont(self.font())
font.setPixelSize(10)
metrics = QFontMetricsF(font)
painter.setFont(font)
painter.setPen(self.palette().color(QPalette.Shadow))
i = 0
while i < 360:
if i % 45 == 0:
painter.drawLine(0, -40, 0, -50)
painter.drawText(-metrics.width(self._pointText[i])/2.0, -52,self._pointText[i])
else:
painter.drawLine(0, -45, 0, -50)
painter.rotate(1)
i += 1
painter.restore()
def drawNeedle(self, painter):
painter.save()
painter.translate(self.width()/2, self.height()/2)
painter.rotate(self._angle)
scale = min((self.width() - self._margins)/120.0,
(self.height() - self._margins)/120.0)
painter.scale(scale, scale)
painter.setPen(QPen(Qt.NoPen))
painter.setBrush(self.palette().brush(QPalette.Shadow))
painter.drawPolygon(
QPolygon([QPoint(-10, 0), QPoint(0, -45), QPoint(10, 0),
QPoint(0, 45), QPoint(-10, 0)])
)
painter.setBrush(self.palette().brush(QPalette.Highlight))
painter.drawPolygon(
QPolygon([QPoint(-5, -25), QPoint(0, -45), QPoint(5, -25),
QPoint(0, -30), QPoint(-5, -25)])
)
painter.restore()
def sizeHint(self):
return QSize(600, 600)
def angle(self):
return self._angle
def setAngle(self, angle):
if angle != self._angle:
self._angle = angle
self.update()
angle = pyqtProperty(float, angle, setAngle)
def animate(self, angle):
self.animation.setStartValue(self._angle)
self.animation.setEndValue(angle)
self.animation.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QWidget()
compass = CompassWidget()
spinBox = QSpinBox()
spinBox.setRange(0, 359)
spinBox.editingFinished.connect(
lambda: compass.animate(spinBox.value()))
layout = QVBoxLayout()
layout.addWidget(compass)
layout.addWidget(spinBox)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
的内容,即使它已被多次不可挽回地借用。 Cell
仅限于实施Cell
的类型(对于您必须使用RefCell
的其他类型),如果涉及多个线程,则必须将Arc
与某些类似的组合使用一个Mutex
)。
Copy
答案 1 :(得分:5)
这完全取决于您的next_gen
功能。假设除了签名之外我们对函数一无所知,最简单的方法是使用索引:
fn step(board: &mut Board) {
for row_index in 0..board.len() {
for column_index in 0..board[row_index].len() {
let cell_next = next_gen((row_index, column_index), &board);
if board[row_index][column_index] != cell_next {
board[row_index][column_index] = cell_next;
}
}
}
}
有关next_gen
的更多信息,可能有不同的解决方案,但这听起来很像我的细胞自动机,据我所知,这不能用Rust中的迭代器方式完成更改Board
的类型。
您可能担心索引解决方案的效率低于迭代器解决方案,但您应该信任LLVM。如果您的next_gen
函数位于另一个包中,则应将其标记为#[inline]
,以便LLVM也可以对其进行优化(如果所有内容都在一个包中,则不需要)。
不是你的问题的答案,而是问题的答案:
由于您正在实施Conway的生命游戏,因此您无法就地进行修改。想象一下以下模式:
00000
00100
00100
00100
00000
如果您更新第2行,它会将该行中的1
更改为0
,因为其附近只有两个1
。这将导致中间1
只能看到两个1
而不是那里开始的三个Board
。因此,您需要复制整个 public void onReceive(Context context, Intent intent) {
// Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (mp.isPlaying()) {
stopPlaying();
mp.stop();
}
else {
stopPlaying();
mp = MediaPlayer.create(context, R.drawable.aaz);
mp.start();
}
}
private void stopPlaying() {
if (mp != null) {
mp.stop();
mp.release();
mp = null;
}}
,或者像在代码中一样,将所有更改写入其他位置,并在遍历整个板后将其拼接。