Имя: Пароль:
1C
 
Массив структур: обращение к элементу при переборе
0 formista2000
 
13.10.25
10:03
Привет!
Есть сабж. Работает по-разному. Почему?
Задача - модифицировать структуру, которая передаётся в качестве параметра.

С таким перебором не работает:
Для Каждого ЭлементМассива Из МойМассив Цикл
    ОбработатьСтруктуру(ЭлементМассива);
КонецЦикла;

А с таким перебором работает:
Для Индекс = 0 По МойМассив.Количество()-1 Цикл
    ОбработатьСтруктуру(МойМассив[Индекс]);
КонецЦикла;

Почему так?

ЗЫ: Массив на клиенте, процедура обработки на сервере.
1 Ненавижу 1С
 
гуру
13.10.25
10:19
Покажите, что вы там меняете в ОбработатьСтруктуру - код с заголовком нужен

По-хорошему надо один раз передать массив на сервер и там все обработать, потом вернуть на клиент
2 Eiffil123
 
13.10.25
10:19
а процедура ОбработатьСтруктуру(ххх)

она точно меняет структуру, а не создает в ней новую? подозрение на второе
3 paramedic
 
13.10.25
10:25
(0) Это смотря что вы делаете в ОбработатьСтруктуру.
4 formista2000
 
13.10.25
10:28
(1) &НаСервереБезКонтекста
Функция ОбработатьСтруктуру(Структ)
    Если Структ.Свойство("МоеСвойство") Тогда
        ...что-то делаем со структурой...
        Результат = 1;
    Иначе
        Структ.Вставить("МоеСвойство", МоеЗначение);
        Результат = 0
    КонецЕсли;
    Возврат Результат;
КонецФункции

Массив передать и обработать полностью сразу не получится, так как при обработке в некоторых случаях надо запрашивать действие пользователя.

Функция вызывается как процедура, так что на Результат не обращайте внимания.

(2) Точно.
5 formista2000
 
13.10.25
10:29
(3) Дополняю своими свойствами структуру.
6 LLeonidov
 
13.10.25
10:35
(0) Да ты прав, воспроизводится.
Отдельно хочу заметить что (1) прав. Вызовы сервера должны быть минимальны. Но, если ты с клиента вызываешь с клиента обработку каких то партий в каждой структуре, по 300 или по 3000штук то это конечно же норм.
Это кст не бага, а фича.
&НаКлиенте
Процедура Структура(Команда)
	МассивСтруктур = Новый Массив;
	
	Для Ном = 0 По 10 Цикл
		Структура = Новый Структура("Ном, Число", Ном, 0);
		МассивСтруктур.Добавить(Структура);
	КонецЦикла;
	
	Сообщить(СтрШаблон("%1: %2", "Базовое", ЗаписьВСтрокуJSON(МассивСтруктур)));
	
	Для Каждого текЭлемент Из МассивСтруктур Цикл
		Добавить1(текЭлемент);
	КонецЦикла;
	
	Сообщить(СтрШаблон("%1: %2", "Перебор ""Для Каждого""", ЗаписьВСтрокуJSON(МассивСтруктур)));
	
	Для Ном = 0 По МассивСтруктур.Количество() - 1 Цикл
		Добавить1(МассивСтруктур[Ном], 10);
	КонецЦикла;
	
	Сообщить(СтрШаблон("%1: %2", "Перебор ""По индексу""", ЗаписьВСтрокуJSON(МассивСтруктур)));
	
КонецПроцедуры 

&НаСервере
Процедура Добавить1(Элемент, Число = 1)
	Элемент.Число = Элемент.Число + Число;
КонецПроцедуры

&НаКлиенте
Функция ЗаписьВСтрокуJSON(Значение, Знач СтруктураОбмена = Неопределено)  Экспорт
	
	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();
	ЗаписатьJSON(ЗаписьJSON, Значение);
	СериализованноеЗначение = ЗаписьJSON.Закрыть();
	
	Возврат СериализованноеЗначение;
КонецФункции
7 maxab72
 
13.10.25
10:40
а почему ОбработатьСтруктуру функция, а вызывается как процедура?

P.S. на обычных формах не воспроизводится.
8 formista2000
 
13.10.25
10:38
(7) это долгая история ))
9 Eiffil123
 
13.10.25
10:43
(0) похоже на баг платформы. было бы в заголовке Знач, тогда поведение было бы ожидаемое.

похожий случай видел, когда массив структур был реквизитом формы, и при изменении структур этот массив не возвращался на клиент если не поправить любой другой реквизит (текст например в другом реквизите).
Но тут то точно должно работать.

регистрируйте в поддержке
10 formista2000
 
13.10.25
10:43
(9) Реквизит формы типа массив?! Да ладно!!11 О.о
11 Мультук
 
гуру
13.10.25
10:45
(0)


0) Я думаю, это просто фича

1)

й = 0;
Для каждого строка из мас Цикл
	//Вот тут строка это всё еще один и тот же указатель с элементом мас. 
		//Т.е Строка=мас[й] это ИСТИНА 
		
	ОбработатьМас(строка);
		//Вот тут строка вернулась из обработки, она хорошая и красивая, но увы
		//она уже сама по себе и 
		//Строка=мас[й] это ЛОЖЬ

	й = й +1;
КонецЦикла;	


P.S.
А будет ли работать вот такой код ?
В применении к массив структур
Имена итераторов то повторяются. Ужас-Ужас

Для каждого строка из мас Цикл
   Для каждого строка из строка Цикл
	Сообщить(Строка.Ключ + ":" + Строка.Значение);
   КонецЦикла;	
КонецЦикла;
12 Chai Nic
 
13.10.25
10:54
(9) "похоже на баг платформы. было бы в заголовке Знач, тогда поведение было бы ожидаемое."

Модификатор Знач влияет только на невозможность изменения передаваемого значения. А структура - это же по сути ссылка, а не само значение. То есть, Знач не должен запрещать изменение значений по ссылке, а только изменение самой ссылки внутри процедуры.

Но здесь клиент-серверный обмен, там при передаче всё сериализуется, так что по идее не должно меняться в обоих случаях, если не происходит обратная сериализация.  Или же должно опять таки в обоих случаях.

Ведь и в том и в другом случае передается элемент массива с типом Структура. И неважно, как мы его получили, по идее. Через итератор или через индекс.
13 Eiffil123
 
13.10.25
10:56
(10) ну да, тип "Произвольный", достаточно часто встречается.
14 formista2000
 
13.10.25
10:57
(13) А, ну да ))
15 Eiffil123
 
13.10.25
10:59
(12) в случае, если Знач у серверной процедуры, а она вызывается с клиента, тогда переданное значение не будет возвращаться, даже если менялось на сервере.

Такие необычные спецэффекты, но надо учитывать.
https://infostart.ru/1c/articles/388527/?ysclid=mgotrlnkp94368307
16 formista2000
 
13.10.25
11:06
(15) Всё правильно. Никаких "Знач" у меня нет.
17 Ненавижу 1С
 
гуру
13.10.25
11:18
При передаче с сервера возвращаются другие объекты (по другим адресам в памяти клиента). Соответственно

Для Каждого ЭлементМассива Из МойМассив Цикл
    ОбработатьСтруктуру(ЭлементМассива);
КонецЦикла;

замещается переменная ЭлементМассива, но она уже отвязана от массива и в массив изменения не попадут

Для Каждого ЭлементМассива Из МойМассив Цикл    
    ПромежуточныйЭлемент = ЭлементМассива;
    ОбработатьСтруктуру(ПромежуточныйЭлемент);  //по окончании это разные структуры
    ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ЭлементМассива, ПромежуточныйЭлемент, Истина);
КонецЦикла;
18 RomanYS
 
13.10.25
11:19
(6) Почему не баг? Никакого разумного объяснения не видно. В какой-то момент на сервере возникает копия структуры и она передается на клиент.
19 Chai Nic
 
13.10.25
11:23
Вообще конечно надо было четко и недвусмысленно заявить, что передача параметров клиент-сервер всегда однонаправленная. А если надо вернуть обратно - пусть возвращают через возвращаемые значения.
20 Ненавижу 1С
 
гуру
13.10.25
11:24
(18) это такой криворукий дизайн языка. Передача параметров зависит от контекста (есть передача между клиентом и сервером или нет)
21 maxab72
 
13.10.25
11:43
(0) Вроде нашел в чем отличие. Действительно, это не баг а фича.

В первом случае ты передаешь на сервер ссылку на структуру с клиента, и получаешь в ответ новую ссылку, во втором случае, при передаче по индексу, ты неявно передаешь весь массив. Если изменить код на:

Для Индекс = 0 По МойМассив.Количество()-1 Цикл
    текЭлемент = МойМассив[Индекс];
    ОбработатьСтруктуру(текЭлемент);
КонецЦикла;

То опять ничего в массиве не поменяется.
22 RomanYS
 
13.10.25
11:51
(21) Блин, почему не баг то? В документации это где-то описано?
Или есть какие-то другие критерии отличия багов от фич? Из общей логики не вижу как можно придти к тому, что это не баг.

(20)👍
23 maxab72
 
13.10.25
11:58
(22) фича в синтаксисе. Смотри, когда ты пишешь: ОбработатьСтруктуру(МойМассив[Индекс]);, ты фактически на сервер, где живет процедура ОбработатьСтруктуру передаешь два параметра: массив целиком и индекс. И все изменения происходят в самом массиве.

А если пишешь текЭлемент = МойМассив[Индекс]; ОбработатьСтруктуру(текЭлемент);
то передаешь на сервер один параметр - ссылку на структуру, без привязки к массиву, и получаешь в ответ ссылку на структуру уже на сервере, а ссылка на структуру на клиенте остается как была неизменной. и массив не меняется.
24 RomanYS
 
13.10.25
12:16
(23) Спасибо. Логику понял. Но принять такое не готов (хотя и выбора вроде нет))
25 Eiffil123
 
13.10.25
13:03
(23) скорее всего не массив катается на сервер, а после десериализации значение структуры помещается в переменную  МойМассив[Индекс], поэтому и значение внутри массива меняется.
26 maxab72
 
13.10.25
13:30
(25) вот нашел в справке: "При передаче управления с клиента на сервер (и обратно) всегда передаются копии параметров. При вызове серверной процедуры или функции с клиента происходит создание копии фактического параметра и передача этой копии на сторону сервера. При возврате управления с сервера на клиента, также происходит создание копии формального параметра (с которым происходила работы в вызванной процедуре или функции) для передачи обратно на клиента." То есть в первом случае: ОбработатьСтруктуру(текЭлемент), возвращается новая ссылка текЭлемент, которая подменяет старую, и массив не меняется, а во втором случае ОбработатьСтруктуру(МойМассив[Индекс]) возвращается новая ссылка на сам массив, и массив изменяется. То есть похоже что гоняется туда-сюда весь массив. Хотя интерпретировать справку можно по разному.
27 Eiffil123
 
13.10.25
13:41
(26) нет, не правильно интерпретируете прочитанное. Массив не передается на сервер. С сервера возвращается новая копия структуры, которая помещается в ту же переменную, которая была до передачи управления на сервер, т.е. в МойМассив[Индекс].

Сам массив на сервер не путешествует, для этого нет оснований
28 RomanYS
 
13.10.25
13:55
(27) Выглядит логичным, но не объясняет бага.
Почему в одном случае переданная ссылка заместилась пришедшей с сервера, а в другом случае зажила своей жизнью.
29 Ненавижу 1С
 
гуру
13.10.25
14:13
(28) потому что ее сразу поместили в массив

например, здесь тоже не обновится:

Для Индекс = 0 По МойМассив.Количество()-1 Цикл
    ПромежуточнаяСтруктура = МойМассив[Индекс];
    ОбработатьСтруктуру(ПромежуточнаяСтруктура);
КонецЦикла;

а если бы все выполнялось на клиенте или только на сервере - обновилось бы
30 maxab72
 
13.10.25
14:17
(27) может и так, результат одинаков.
(28) наоборот, в случае ОбработатьСтруктуру(текЭлемент), возвращается новая ссылка, которая замещает ссылку в переменной текЭлемент. а во втором случае ОбработатьСтруктуру(МойМассив[Индекс]) замещается ссылка в переменной МойМассив, и массив получает новые значения.
31 Chai Nic
 
13.10.25
16:33
Зря они так. Конечно, этим упростили программирование, но создали сложнонаходимые грабли.
32 Timon1405
 
13.10.25
16:46
(29) Использование Знач в процедурах и функциях#96
на второй заход обсуждения тем пошли, а всего-то 10 лет прошло)
33 Eiffil123
 
13.10.25
19:27
(31) Да не, это очень редкие грабли. скорее показывают, что так делать не надо. На клиенте должен быть только клиент, а код заполнения, обработки данных, валидации - всё на сервере.