На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Непонятки
    Туплю! :whistle:
    непойму как сохранить адреса виртуальных фунций. Выбрасывает ошибку 'Incompatible types: 'System.SysUtils.TFunc<System.TFunc<System.string>' and 'string''
    ExpandedWrap disabled
      type
        IVoice = interface
          function Voice: string;
        end;
       
        TAnimal = class abstract (TInterfacedObject)
        private
          FName: string;
        public
          property Name: string read FName write FName;
        end;
       
       
        TDog = class(TAnimal, IVoice)
        public
          function Voice: string;
        end;
       
        TCat = class(TAnimal, IVoice)
        public
          function Voice: string;
        end;
       
      { TDog }
       
      function TDog.Voice: string;
      begin
        Result:= 'Arf-Arf!';
      end;
       
      { TCat }
       
      function TCat.Voice: string;
      begin
        Result:= 'Meow-Meow!';
      end;
       
      var
        voices: TArray<IVoice>;
        funcs: TArray<TFunc<string>>;
        I: Integer;
      begin
        voices:= [TDog.Create, TCat.Create, TDog.Create];
        SetLength(funcs, Length(voices));
       
        for I := 0 to High(voices) do
          funcs[i]:= voices[i].Voice;  //<--- это вызов, а надо сохранить адрес функции    
        Readln;
      end.

    Хелп плз! :whistle:
      А вот если убрать интерфейс IVoice и заюзать абстрактный класс TAnimal то все пашет, адреса сохраняются! :wall:
      ExpandedWrap disabled
        type
          TAnimal = class abstract
          private
            FName: string;
          public
            function Voice: string; virtual; abstract;
            property Name: string read FName write FName;
          end;
         
         
          TDog = class(TAnimal)
          public
            function Voice: string; override;
          end;
         
          TCat = class(TAnimal)
          public
            function Voice: string; override;
          end;
         
        { TDog }
         
        function TDog.Voice: string;
        begin
          Result:= 'Arf-Arf!';
        end;
         
        { TCat }
         
        function TCat.Voice: string;
        begin
          Result:= 'Meow-Meow!';
        end;
         
        var
          animals: TArray<TAnimal>;
          funcs: TArray<TFunc<string>>;
          I: Integer;
        begin
          animals:= [TDog.Create, TCat.Create, TDog.Create];
          SetLength(funcs, Length(animals));
         
          for I := 0 to High(animals) do
            funcs[i]:= animals[i].Voice; //<--- а вот так все пучком!
         
          // тест
          for I := 0 to High(funcs) do
            Writeln(funcs[i]());
         
          Readln;
        end.

      Я в непонятках :wall:
      Где я не доучил Объект Паскаль? :wacko:
      Кстати учу по книжке моего кента Марко Кента :lool:
      Сообщение отредактировано: Cfon -
        Cfon
        Это косяк эмбаркодеров. Они толком не за документировали и как следствие толком не закодировали.
          Цитата Pavia @
          Cfon
          Это косяк эмбаркодеров. Они толком не за документировали и как следствие толком не закодировали.

          Решил их косяк через анонимку :D
          ExpandedWrap disabled
            begin
              voices:= [TDog.Create, TCat.Create, TDog.Create];
              SetLength(funcs, Length(voices));
             
              for I := 0 to High(voices) do
                (procedure (i: integer)  //<--- iife
                  funcs[i]:= function: string //<--- anonimous function
                  begin
                    Result := voices[i].Voice;
                  end;
                end)(i);
             
              for I := 0 to High(funcs) do
                Writeln(funcs[i]());
             
              Readln;
            end.



          в JS стиле :D
          ExpandedWrap disabled
            begin
              var voices: TArray<IVoice>:= [TDog.Create, TCat.Create, TDog.Create];
              var funcs: TArray<TFunc<string>>;
             
              SetLength(funcs, Length(voices));
             
              for var I := 0 to High(voices) do
                (procedure (i: integer)
                 begin
                  funcs[i]:= function: string
                    begin
                      Result := voices[i].Voice;
                    end;
                 end)(i);
             
              for var I := 0 to High(funcs) do
                Writeln(funcs[i]());
             
              Readln;
            end.

          похоже тока в JS не надо указывать типы :D
          да и память не надо в ручную выделять :D

          ПС. Меня за уши теперь от Делфи не отянуть :lool:
          Формочки набиваются на раз два + код паскаля простой, легко читаемый, это просто мечта прогера :D
          Сообщение отредактировано: Cfon -
            ExpandedWrap disabled
              for var I := 0 to High(voices) do
                  (procedure (i: integer)  //<--- iife
                    funcs[i]:= function: string //<--- anonimous function
                    begin
                      Result := voices[i].Voice;
                    end;
                  end)(i);

            Отдельно хочу пояснить про iife (самовызываемая функция) во втором цикле for, она создает локальную область видимости. Зачем? Затем чтобы анонимная функция сохранила переменную i в ней!
            Я хз почему, но анонимка не замыкает локальную переменную i цикла for! Мои эксперементы с ней показали что она удалятся после цикла :whistle:
            В итоге если не создать вручную локалку мы имеем эксепшен при доступе к массиву funcs. Наверно очередной косяк Эмбаркадэро :wacko:

            А вот на JS найди отличия :D
            ExpandedWrap disabled
              for (var i=0; i < voices.length; i++)
                  (function (i) { //<--- iife
                    funcs.push( function () { //<--- anonimous function
                      return voices[i].Voice;
                    }
                  })(i);
            Сообщение отредактировано: Cfon -
              Цитата Cfon @
              Мои эксперементы с ней показали что она удалятся после цикла
              В итоге если не создать вручную локалку мы имеем эксепшен при доступе к массиву funcs.

              Тикет qc создал надеюсь? Я б проголосовал.
                Цитата jack128 @
                Цитата Cfon @
                Мои эксперементы с ней показали что она удалятся после цикла
                В итоге если не создать вручную локалку мы имеем эксепшен при доступе к массиву funcs.

                Тикет qc создал надеюсь? Я б проголосовал.

                Упс, пардон ми :D
                Я поспешил с выводами переменная i не удалятся, замыкание есть, но все 3 вызова в цикле захватывают одну и туже i и итоге при обращении у массиву функций идет обращение по индексу i=3 что ведет к эксепшену обращение за пределы массива. Похожая ситуация есть в JS тока там var i определенная в цикле имеет глобальную область действия, а в Delphi она локальная. Короче тут все без косяков, это просто фича цикла for и анонимок. Переменные захватываются по ссылке, а не по значению, чтобы решить траблу надо заюзать iife создавая на каждой итерации новую локалку. В JS ввели let для определения локальной переменной, как она работает я не разбрал, кажись анонимки захватывают ее по значению точно не помню, потому в JS можно решить это так :)
                ExpandedWrap disabled
                  for (let i=0; i < voices.length; i++)
                  // iife не надо ибо захват i по значению  
                      funcs.push( function () {
                        return voices[i].Voice;
                      }
                Сообщение отредактировано: Cfon -
                  Цитата Cfon @
                  Я поспешил с выводами переменная i не удалятся, замыкание есть, но все 3 вызова в цикле захватывают одну и туже i и итоге при обращении у массиву функций идет обращение по индексу i=3 что ведет к эксепшену обращение за пределы массива.


                  по идее - это тоже касяк. То есть, если мы объявили i в var блоке функции - то такое поведение логично, а если мы объявили i в цикле, то захвачено должно на каждой итерации - отдельное значение.

                  Вообще смешно это, абракадабра заимствует многое из C# при этом повторяя их же ошибки. В шарпе изначально было такое же поведение, но несколько лет назад они фиксанули это и теперь захват значения в лямбду происходит как будто у нас на каждой итерации новая переменная i с новым значением (как c let в js)
                  Сообщение отредактировано: jack128 -
                    Цитата
                    ExpandedWrap disabled
                      funcs[i]:= voices[i].Voice;  //<--- это вызов, а надо сохранить адрес функции

                    Эээ, а так разве не то, что требуется?
                    ExpandedWrap disabled
                      funcs[i]:= @voices[i].Voice;
                      Цитата Fr0sT @
                      Эээ, а так разве не то, что требуется?
                      funcs[i]:= @voices[i].Voice;

                      так - это то что даже не компилится
                        Ну ему нужен адрес функции - он берется вот так.
                          Нет. Чтобы взять адрес функции, справа от оператора @ должна быть функция, а Voices[I].voice - это метод интерфейса. в Дельфи нет возможности взять его адрес.
                          upd: встроенной возможности.
                          Сообщение отредактировано: jack128 -
                            Цитата Fr0sT @
                            Цитата
                            ExpandedWrap disabled
                              funcs[i]:= voices[i].Voice;  //<--- это вызов, а надо сохранить адрес функции

                            Эээ, а так разве не то, что требуется?
                            ExpandedWrap disabled
                              funcs[i]:= @voices[i].Voice;

                            Ошибка [dcc32 Error] : E2036 Variable required

                            Ну да фиг с ним :D
                            Продолжаю улучшения скрываем цикл for, функциональщина так и прет :D
                            ExpandedWrap disabled
                              type
                                TForEachProc<T> = reference to procedure (Value: T; Index: Integer);
                               
                                TArrayHelper = class helper for TArray
                                  class procedure ForEach<T>(const Values: array of T; AProc: TForEachProc<T>); static;
                                end;
                               
                              { TArrayHelper }
                               
                              class procedure TArrayHelper.ForEach<T>(const Values: array of T; AProc: TForEachProc<T>);
                              begin
                                for var I := 0 to High(Values) do
                                  AProc(Values[I], I);
                              end;
                               
                              var
                                voices: TArray<IVoice>;
                                funcs: TArray<TFunc<string>>;
                              begin
                                voices:= [TDog.Create, TCat.Create, TDog.Create];
                                SetLength(funcs, Length(voices));
                               
                                TArray.ForEach<IVoice>(voices, procedure (elem: IVoice; i: integer)
                                begin
                                  funcs[i]:= function: string
                                    begin
                                      Result:= elem.Voice;
                                    end;
                                end);
                               
                                // тест
                                for var i := 0 to High(funcs) do
                                  Writeln(funcs[i]());
                               
                                Readln;
                              end.

                            ПС. обратите внимание тут iife уже не требуется поскольку наши операторы заключены в анонимку.
                            Сообщение отредактировано: Cfon -
                              Улучшаем предыдущий код, убираем выделение памяти для массива funcs! :D
                              Для этого допишем TArrayHelper, а именно создадим функцию Map и заменим в коде ForEach на Map.
                              Кто не в теме функциональной парадигмы поясню: Map получает на входе исходный массив а возвращает другой массив, попутно выполняя какие либо преобразования исходного массива.
                              ExpandedWrap disabled
                                type
                                  TForEachProc<T> = reference to procedure (Value: T; Index: Integer);
                                  TMapProc<T, R> = reference to function (Value: T; Index: Integer): R;  
                                 
                                  TArrayHelper = class helper for TArray
                                    class procedure ForEach<T>(const Values: array of T; AProc: TForEachProc<T>); static;
                                    class function Map<T, R>(const Values: array of T; AProc: TMapProc<T, R>): TArray<R>; static;    
                                  end;
                                 
                                { TArrayHelper }
                                 
                                .....
                                 
                                class function TArrayHelper.Map<T, R>(const Values: array of T;
                                  AProc: TMapProc<T, R>): TArray<R>;
                                begin
                                  Result:= [];
                                  for var I := 0 to High(Values) do
                                    Result:= Result + [AProc(Values[i], i)];
                                end;
                                 
                                begin
                                  var voices: TArray<IVoice> := [TDog.Create, TCat.Create, TDog.Create];
                                 
                                  var funcs := TArray.Map<IVoice, TFunc<string>>(voices,
                                    function (v: IVoice; i: integer): TFunc<string>
                                    begin
                                      Result:= function: string
                                        begin
                                          Result := v.Voice;
                                        end;
                                    end);
                                 
                                  // test
                                  for var fn in funcs do Writeln(fn());
                                 
                                  Readln;
                                end.

                              В итоге никаких тебе явных выделений памяти и циклов.
                              Обращаю внимание что при объявлении переменная funcs не указан её тип, тут работает выведение типов, а вот при объявление voices требуется указать тип ибо тут выведеный тип не подходит, поскольку нам надо TArray<IVoice>, а компилятор нам предлагает array of const, что делать? укажем вручную :D
                              ПС. в мапе я заюзал конкатенацию массивов, но можно и через SetLength.
                              Сообщение отредактировано: Cfon -
                                по поводу inline variables вот
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0561 ]   [ 17 queries used ]   [ Generated: 20.04.24, 02:42 GMT ]