Добавление значения в общую коллекцию в классе не разрешено из-за области действия

У меня возникают проблемы при добавлении элементов в объект, который хранит коллекцию значений общего типа. Я пробовал минимальный рабочий пример, который вызывает ошибку:

class OneElementQueue {

    type eltType;

    var elements : [0..0] eltType;

    //initializer
    proc init(type eltType) {
        this.eltType = eltType;
    }

    proc add(element : eltType) {
        this.elements[0] = element;
    }

    proc remove() : eltType {
        return this.elements[0];
    }   
} //end of OneElementQueue

class Monkey {

    var name: string;
    var age: int;

    proc init(name : string, age : int) {
        this.name = name;
        this.age = age;
    }

} //end of class Monkey


var q = new owned OneElementQueue(Monkey);
var m = new owned Monkey("Kyle", 6);
q.add(m);

Когда я пытаюсь скомпилировать все это, я получаю сообщение об ошибке:

$ chpl BadQueue.chpl
BadQueue.chpl:12: In function 'add':
BadQueue.chpl:13: error: Scoped variable would outlive the value it is set to
BadQueue.chpl:12: note: consider scope of element
$

Как правильно добавить что-то в общую структуру данных, подобную этой? Как я поступаю об этом неправильно?

1 ответ

Решение

Здесь есть два возможных подхода, в зависимости от того, какое поведение вы хотите:

"Я хочу, чтобы моя коллекция стала владельцем объектов Обезьяны"

В этом случае вы захотите создать экземпляр OneElementQueue коллекция для хранения owned Monkey объекты, а не просто [borrowed] Monkey объекты, которые по умолчанию для типов классов. Вы можете сделать это с одной строкой изменения (попробуйте онлайн):

var q = new owned OneElementQueue(owned Monkey);

В этом подходе, передавая owned Monkey на ваш add() Метод передает владение аргументу и, в конечном итоге, коллекции, делая исходную ссылку на объект недействительной (nil).

"Я хочу, чтобы моя коллекция заимствовала существующие объекты Обезьяны, не принимая их в собственность"

В этом случае вам нужно сообщить add() метод, которым аргумент, переданный в него, переживет сам аргумент (и затем будет уверен, что не лжет об этом). В версии 1.19 Chapel это можно сделать с помощью аннотаций на весь срок службы:

proc add(element : eltType) lifetime element > this {

где аннотация lifetime element > this утверждает, что фактический аргумент прошел через element переживет this сама коллекция, поэтому компилятор не должен бояться, что заимствование прекратится, как только появится формальный аргумент.

Пожизненные аннотации не были доступны в Chapel 1.18, поэтому, если вы используете эту версию, вам нужно использовать немного больший молоток и применить pragma "unsafe" к методу. Обратите внимание, что прагмы не являются официально поддерживаемой функцией и могут измениться в будущем, поэтому в этом случае она служила временным ограничением до тех пор, пока не были реализованы аннотации времени жизни (попробуйте онлайн):

pragma "unsafe"
proc add(element : eltType) {
Другие вопросы по тегам