Um dos desafios de codificação mais interessantes dados a mim para uma entrevista foi criar uma fila funcional. O requisito era que cada chamada para enfileirar criaria uma nova fila que contivesse a fila antiga e o novo item na cauda. Retirar da fila também retornaria uma nova fila e o item retirado da fila como um parâmetro externo.
Criar um IEnumerator a partir desta implementação seria não destrutivo. E deixe-me dizer-lhe que implementar uma fila funcional com bom desempenho é muito mais difícil do que implementar uma pilha funcional de alto desempenho (a pilha Push / Pop funciona na cauda, pois uma fila enfileira funciona na cauda, a desenfileiramento funciona na cabeça).
Meu ponto de vista é ... é trivial criar um Enumerador de Pilha não destrutivo implementando seu próprio mecanismo de Ponteiro (StackNode <T>) e usando a semântica funcional no Enumerador.
public class Stack<T> implements IEnumerator<T>
{
private class StackNode<T>
{
private readonly T _data;
private readonly StackNode<T> _next;
public StackNode(T data, StackNode<T> next)
{
_data=data;
_next=next;
}
public <T> Data{get {return _data;}}
public StackNode<T> Next{get {return _Next;}}
}
private StackNode<T> _head;
public void Push(T item)
{
_head =new StackNode<T>(item,_head);
}
public T Pop()
{
//Add in handling for a null head (i.e. fresh stack)
var temp=_head.Data;
_head=_head.Next;
return temp;
}
///Here's the fun part
public IEnumerator<T> GetEnumerator()
{
//make a copy.
var current=_head;
while(current!=null)
{
yield return current.Data;
current=_head.Next;
}
}
}
Algumas coisas a serem observadas. Uma chamada para enviar ou enviar antes da instrução current = _head; concluídas forneceria uma pilha diferente para enumeração do que se não houvesse multithreading (convém usar um ReaderWriterLock para proteger contra isso). Eu fiz os campos no StackNode somente leitura, mas é claro que se T é um objeto mutável, você pode alterar seus valores. Se você criar um construtor Stack que utilizou um StackNode como parâmetro (e defina o cabeçalho como o passado no nó). Duas pilhas construídas dessa maneira não terão impacto uma na outra (com exceção de um T mutável, como mencionei). Você pode enviar por push e pop o quanto quiser em uma pilha, a outra não será alterada.
E que meu amigo é como você faz a enumeração não destrutiva de uma pilha.