Этот вопрос написан на псевдо-PHP, но я действительно не возражаю против того, на каком языке я получаю ответы (кроме Ruby :-P), так как это чисто гипотетически. На самом деле, PHP, возможно, является худшим языком для такой логики. К сожалению, я никогда не делал этого раньше, поэтому не могу привести пример из реальной жизни. Поэтому гипотетические ответы вполне приемлемы.
В принципе, у меня много объектов, выполняющих задачу. Для этого примера, скажем, каждый объект является классом, который загружает файл из Интернета. Каждый объект будет загружать отдельный файл, а загрузки выполняются параллельно. Очевидно, что некоторые объекты могут закончить загрузку раньше других. Фактический сбор данных может выполняться в потоках, но это не относится к этому вопросу.
Таким образом, мы можем определить объект так:
class DownloaderObject() {
var $url = '';
var $downloading = false;
function DownloaderObject($v){ // constructor
$this->url = $v;
start_downloading_in_the_background(url=$this->$url, callback=$this->finished);
$this->downloading = true;
}
function finished() {
save_the_data_somewhere();
$this->downloading = false;
$this->destroy(); // actually destroys the object
}
}
Хорошо, у нас работает много таких объектов:
$download1 = new DownloaderObject('http://somesite.com/latest_windows.iso');
$download2 = new DownloaderObject('http://somesite.com/kitchen_sink.iso');
$download3 = new DownloaderObject('http://somesite.com/heroes_part_1.rar');
И мы можем хранить их в массиве:
$downloads = array($download1, $download2, $download3);
Итак, у нас есть массив, полный загрузок:
array(
1 => $download1,
2 => $download2,
3 => $download3
)
И мы можем перебирать их так:
print('Here are the downloads that are running:');
foreach ($downloads as $d) {
print($d->url . "\n");
}
Хорошо, теперь предположим, что загрузка 2 завершена, и объект уничтожен. Теперь у нас должно быть два объекта в массиве:
array(
1 => $download1,
3 => $download3
)
Но в массиве есть дыра! Ключ № 2 не используется. Кроме того, если я хотел начать новую загрузку, неясно, куда вставить загрузку в массив. Может работать следующее:
$i = 0;
while ($i < count($downloads) - 1) {
if (!is_object($downloads[$i])) {
$downloads[$i] = new DownloaderObject('http://somesite.com/doctorwho.iso');
break;
}
$i++;
}
Однако, это ужасно неэффективно (и циклы while $i++
- это нуби). Итак, другой подход заключается в том, чтобы сохранить счетчик.
function add_download($url) {
global $downloads;
static $download_counter;
$download_counter++;
$downloads[$download_counter] = new DownloaderObject($url);
}
Это бы сработало, но мы все равно получили дыры в массиве:
array(
1 => DownloaderObject,
3 => DownloaderObject,
7 => DownloaderObject,
13 => DownloaderObject
)
Это ужасно. Однако это приемлемо? Должен ли массив быть «дефрагментированным», т. Е. Переставить ли ключи для устранения пробелов?
Или есть другая программная структура, о которой я должен знать? Мне нужна структура, в которую я могу добавлять вещи, удалять их, ссылаться на ключи в переменной, выполнять итерации и т. Д., Это не массив. Существует ли такая вещь?
Я кодировал годами, но этот вопрос беспокоил меня очень много лет, и я до сих пор не знаю ответа. Это может быть очевидным для некоторых программистов, но для меня это весьма нетривиально.