Я хотел бы, чтобы † при постановке ‡ в git
репо, если изменения, которые я собираюсь зафиксировать, содержат определенную строку (скажем, @ todo
или @ hack
).
Может ли кто-то показать мне, как этого добиться?
† или предупрежден.
‡ или при совершении.
Я прохожу через Programming In Scala 2-го издания Odersky, Spoon и Venners, и этот пример бросил меня на петлю, поскольку он, казалось, идет вразрез с тем, что я думал о функциональном программировании и неизменности. В примере (и ранее в книге в гл. 18) авторы утверждают, что операции над объектом все еще могут быть «чисто функциональными», даже когда эти операции могут внутренне мутировать состояние объекта. Пример, который есть на стр. 442, гл. 19, таков:
class Queue[+T] private (
private[this] var leading: List[T],
private[this] var trailing: List[T]
) {
private def mirror() =
if (leading.isEmpty) {
while (!trailing.isEmpty) {
leading = trailing.head :: leading
trailing = trailing.tail
}
}
def head: T = {
mirror()
leading.head
}
def tail: Queue[T] = {
mirror()
new Queue(leading.tail, trailing)
}
def enqueue[U >: T](x: U) =
new Queue[U](leading, x :: trailing)
}
Приведенное обоснование состоит в том, что, пока это побочные эффекты не видны клиентам, что-то подобное можно считать функциональным. Я думаю, я могу отстать от этого... Я имею в виду строго говоря, это то, что определяет функцию. Но надо признать (и я на самом деле не слишком осведомлен о том, что гарантирует модель памяти JVM), но разве нет потенциальных проблем с этим в этом коде?
Например, если два потока выполняют операции в этой очереди, которая выглядит следующим образом:
Leading: Nil
Trailing: List(1,2,3,4)
Разве не возможно, что один поток может вызвать head (), добравшись до этой точки зеркала (), прежде чем он будет отменен:
private def mirror() =
if (leading.isEmpty) {
while (!trailing.isEmpty) {
leading = trailing.head :: leading
> trailing = trailing.tail
}
}
В этот пункт очередь выглядит следующим образом:
Leading: List(1)
Trailing: List(1,2,3,4)
И когда второй поток вызывает tail (), когда первый не активен, возвращается следующее:
Leading: Nil
Trailing: List(1,2,3,4)
Если вызов head () первого потока завершится, то он будет возвращен после последующего вызова tail () в этом списке:
Leading: List(2,3,4)
Trailing: Nil
Я признаю, что не очень хорош в таких вещах, и параллельное программирование для меня очень важно, так как я уверен, что это для многих людей, мне просто любопытно, чего мне здесь не хватает.