在不同 Perl 版本下运行的程序之间传递对象

2024-02-13

使用从 perl5.6.pl 到 perl5.24.pl 的不同 perl 版本将对象作为输入参数传递时遇到问题(无法从函数“$from_5.24”获取返回值)。下面提供了有问题的代码。使用windows平台,如何解决这个问题。

SharedBetweenPerls.pm:

package SharedBetweenPerls;
use warnings;
use strict;
use Exporter;
our @ISA = 'Exporter';
our @EXPORT_OK = qw(getVal);

sub new {
   my $self = {
      roleId => undef,
      username => undef,
   };
   bless $self, 'SharedBetweenPerls';
   return $self;
}

sub getVal{
  my ($self) = @_;
  return $self->{'roleId'};
}
1;

v5.24.pl:

use warnings;
use strict;
use v5.24;
use lib '.';
my ($self) = @_;
print $self->{'roleId'}; # Not working

v5.6.pl:

use warnings;
use strict;
use lib '.'; 
use SharedBetweenPerls;

my $obj =  new SharedBetweenPerls();
$obj->{'roleId'} = '10000';
$obj->{'username'} = 'test123';

my $roleId = $obj->getVal();
print "Value : $roleId \n"; # working fine

my $from_5.24 = qx(path-to-perl-5.24 program_for_5.24.pl "$obj"); 
print "Return from function: $from_5.24"; # Not Working

我尝试使用 zdim 给出的序列化测试代码(SharedBetweenPerls.pm)。我遇到以下格式错误。

malformed JSON string, neither tag, array, object, number, string or atom, at character offset 0 (before "roleId") at SharedBetweenPerls.pm

5.6.pl:

use warnings;
use strict;
use lib '.'; 
use SharedBetweenPerls;
use IPC::System::Simple qw(capturex);
#my $data = '{"roleId":31, "username":"test123"}';
#my $obj = SharedBetweenPerls->new($data);
my $obj = SharedBetweenPerls->new(roleId => 17, username => 'test123');
my $result = capturex('D:\Perl\bin\perl524.exe', 'D:\sample_program\p5.24.pl', '$obj->serialize');
print "return from function: $result";

5.24.pl:

use warnings;
use strict;
use v5.24;
use lib '.';
use SharedBetweenPerls;
my ($init_json) = @ARGV;
my $obj = SharedBetweenPerls->new( $init_json );
print $obj->{'roleId'};

Note   下面有两种序列化方法——使用Storable(考虑到它需要在不同的 Perl 和模块版本之间,可能会出现问题),以及自定义版本


这是该问题的更一般情况上一个问题 https://stackoverflow.com/q/61053765/4653379,现在要在程序之间传递对象。这一变化带来了实质性的差异。

一个对象必须是连载的 https://en.wikipedia.org/wiki/Serialization为了传递,这样我们就可以通过某种管道逐字节传递它。我用Storable https://perldoc.perl.org/Storable.html为此目的,在此演示中,但您可能需要寻找其他工具或者编写自定义流程(在最后添加的部分展示)

以下是文件,还有一些其他调整(将在下面讨论)。

套餐SharedBetweenPerls.pm

package SharedBetweenPerls;    
use warnings;
use strict;

sub new {
    my ($class, %args) = @_; 
    my $self = { %args };
    return bless $self, $class;
}

sub get_roleId {
    my ($self) = @_; 
    return $self->{'roleId'};
}

1;

v5.24下需要运行的程序(v.5.24.pl)

use warnings;
use strict;

use Storable qw(retrieve);

use v5.24;    

use FindBin qw($RealBin); 
use lib $RealBin;       # look for modules in this script's directory
use SharedBetweenPerls;

my ($file) = @ARGV;

my $obj = retrieve($file) // warn "There were errors: $!";

print $obj->get_roleId;

“主”程序,必须在较旧的 Perl 下运行

use warnings;
use strict;
use feature 'say';

use Storable qw(store);

use FindBin qw($RealBin); 
use lib $RealBin;   
use SharedBetweenPerls;

my $obj = SharedBetweenPerls->new(roleId => 17, username => 'test123');

my $roleId = $obj->get_roleId();
say "Value for 'roleId' in the new object: $roleId";

my $outfile = "obj_$$.storable";  # store the serialized object in a file
store($obj, $outfile) // warn "There were errors: $!";                 #/

# (replace my perlbrew path with your actual path to the v5.24 executable)
my $perl_524 = qq($ENV{HOME}/perl5/perlbrew/perls/perl-5.30.0/bin/perl);
my $cmd = qq($perl_524 v5.24.pl $outfile);
my $from_524 = qx( $cmd );
chomp $from_524;    
say "Return from function: $from_524";

unlink $outfile or warn "Can't unlink $outfile: $!";  # can delete file now

写入序列化对象的文件的名称应该比我在本演示中使用的名称好得多,并且文件::临时文件 https://perldoc.perl.org/File/Temp.html是处理临时名称的标准选择。

这打印



Value for 'roleId' in the new object: 17
Return from function: 17
  

因此,对于这个简单的玩具类来说,这是可行的——对象被正确传递。

然而,连载绝不是一件小事。根据您的实际类的复杂程度,特别是两个程序的模块版本的差异程度,可能会出现问题。对于 v5.6 和 v5.24 的组合,我认为您需要祈祷。 (它适用于我的 v5.16 和 v5.30,但 v5.6 非常非常旧。)

组合store+retrieve是使用文件传递复杂数据的(一种方法)。我也尝试过freeze对象并手动将其写入文件,然后读取该文件并thaw它,而且也有效。 (将冷冻物体直接通过管道传递会很麻烦。)

但是传递整个对象可能不起作用,如果您的情况确实存在问题,那么该怎么做将完全取决于您的类的实际情况。

One thing you can always do is to come up with a custom serialization approach, whereby needed data is passed along (via a file or suitably serialized for a pipe), not the whole object. Then the program on the other end can use that to construct the object.

如果使用文件传递数据,什么是明确的选项,那么我们正在讨论坚持 https://en.wikipedia.org/wiki/Persistence_(computer_science).

Comments

  • 当包定义类时,没有理由导出符号

  • 不要硬编码包名称;有__PACKAGE__为了那个原因。但是对于一个类,包名称作为构造函数中的第一个参数传递,并且应该使用它

  • 不要将对象用作任何旧的哈希引用,在这种情况下,只需取消引用键即可打印值。这会触及类的内部结构,并且是一个非常非常糟糕的主意——使用提供的方法。 (为此v.5.24.pl程序也需要加载带有类的包)

  • 如果你希望被调用的程序能够使用一个对象,它应该加载定义该类的包(因为不应该将该对象用作纯粹的哈希引用)

  • The 间接方法表示法 https://perldoc.perl.org/perlobj.html#Invoking-Class-Methods (new ClassName)非常值得避免。请改用普通方法调用(ClassName->new)。一方面,构造函数is一个方法

  • 程序的参数位于@ARGV,不在@_

  • 上面的类需要更多,但这会带我们去别的地方

  • 我建议使用模块来运行外部命令,而不是反引号(qx)。尝试一些:IPC::System::Simple, Capture::Tiny, IPC::Run3, IPC::Run


An example

向您的类添加一个方法来实现所需的反/序列化。它可以简单地创建一个包含所有属性及其值的哈希,然后将其序列化——例如,从中生成一个 JSON 字符串。 (如果某些属性的值是其他类的对象,那么您必须做更多的工作。)

然后v5.6.pl程序可以做(使用IPC::系统::简单 https://metacpan.org/pod/IPC::System::Simple模块在这里)

use IPC::System::Simple qw(capturex);
...
my $from_524 = capturex($perl_524, 'v5.24.pl', $obj->serialize);

and the v.5.24.pl然后程序可以做

my ($init_json) = @ARGV;

my $obj = SharedBetweenPerls->new( $init_json );

现在目标程序已经有了一个用所需数据构建的对象并且可以开始工作了。

这里有一个非常基本和粗暴例子。请注意,对于您的项目来说,这可能是一个糟糕的选择,我对此一无所知,而如果可以使用它,则需要更多的工作/检查。

我使用 JSON 来序列化属性及其值的哈希值;这是在serialize方法。然后这样的 JSON 字符串可以用来构造一个新对象:构造函数检查它是否获得了 hashref 或者字符串,对于字符串,它调用一个方法(init_from_json) 初始化对象。

sub new {                              # WARNING: a sketchy demo only
    my ($class, $args) = @_; 
    my $self = {}; 
    bless $self, $class;
    my $ref = ref $args;
    if (not $ref) {                    # a string; better be JSON
        $self->init_from_json($args);
    }   
    elsif ($ref eq 'HASH') {           # straight-up attributes, initialize
        $self->{$_} = $args->{$_}  for keys %$args;
    }   
    else { croak "Unsupported invocation..." }  # print user message etc
    return $self;
}

sub serialize {
   my $self = shift;
    require JSON; JSON->import('encode_json');
    my %attr = map { $_ => $self->{$_} } keys %$self;
    return encode_json(\%attr);  # (no objects please)
}

sub init_from_json {
    my ($self, $args_json) = @_; 
    require JSON; JSON->import('decode_json');
    my $args = decode_json($args_json);
    $self->{$_} = $args->{$_} for keys %$args;
}

...

Now the v5.6.pl程序可以创建它的对象并序列化它,然后调用v5.30.pl将该 JSON 字符串作为输入传递给它的程序。这v5.30.pl然后程序可以从 JSON 重建对象并使用它来完成工作。

根据具体情况,还有许多其他方法可以做到这一点。

如果您要使用面向对象代码的框架,例如Moose or Moo,那么就有现成的工具和技术可以提供帮助。 (如果您没有使用过这些框架,那么还会有一些学习曲线。)


根据要求,完整的工作程序(最大限度地简化以帮助调试)

v5.6.pl

use warnings;
use strict;
    
use IPC::System::Simple qw(capturex);

use FindBin qw($RealBin); 
use lib $RealBin;   
use SharedBetweenPerls;

my $obj = SharedBetweenPerls->new( { roleId => 17, data => [3..7] } );

# (replace my perlbrew path with your actual path to the v5.24 executable)
my $perl_524 = qq($ENV{HOME}/perl5/perlbrew/perls/perl-5.30.0/bin/perl);

my $from_524 = capturex( $perl_524, 'v5.30.pl', $obj->serialize );
print "Return from function: $from_524";

v5.30.pl

use warnings;
use strict;

use v5.24;
use FindBin qw($RealBin); 
use lib $RealBin;   
use SharedBetweenPerls;

my ($init_json) = @ARGV;

my $obj = SharedBetweenPerls->new($init_json);
print $obj->get_roleId;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在不同 Perl 版本下运行的程序之间传递对象 的相关文章

  • 为什么我的 Apache2::Log 输出用 \n 替换换行符?

    我在 apache2 mod perl 下设置了多个虚拟主机 我用的是ErrorLog指令为每个虚拟主机获取单独的错误日志 仅当我使用 Apache2 Log 时 这才按预期工作 警告 只会记录到常规错误日志中 这样就可以了 最后 但还存在
  • 如何在 Perl 中循环访问类的所有方法?

    如何在 Perl 中循环访问一个类的所有方法 有没有关于 Perl 内省或反射的好的在线参考 Todd Gardner 使用 Moose 的建议很好 但他选择的示例代码并不是很有帮助 如果你正在检查一个非 Moose 使用类 你会这样做 u
  • Perl regex:如何知道匹配数

    我循环遍历一系列正则表达式并将其与文件中的行进行匹配 如下所示 for my regex regexs ref LINE for rawfile regex do do something here next LINE 有没有办法让我知道我
  • 使用 Visual Studio Code 调试 Perl

    我今天刚开始使用 Perl 并安装了活动Perl https en wikipedia org wiki ActivePerl5 24 1 一切都很顺利 我能够创建我的测试程序testPerl pl与简单的print命令并运行它consol
  • python 3中pickle和_pickle有什么区别?

    我是 python 新手 想要实现fast对象序列化 我尝试使用json 但是太慢了 也尝试使用marshall模块 但是marshall序列化的对象的大小比pickle大6 7倍 所以我决定在我的项目中使用pickle 我读到了有关 cP
  • 将属性反序列化到预先存在的对象中

    是否可以使用任何标准序列化程序来反序列化对象属性 而无需创建新对象 问题是 所讨论的对象非常复杂 它们只能由特殊工厂创建 并且它们的类型是在运行时动态生成的 但它们有一些已知的属性 我想将它们存储在外部文件 最好是 xml 但二进制也可以
  • 使用 iostream << 序列化用户对象

    我想使用运算符 ofstream out file ios out ios binary int i 0xAA out lt lt i 并输出 0x31 0x37 0x30 即 0xAA gt 170 170 如果我使用 write 函数
  • 将 stdin/stdout 从执行进程重定向到 Perl 中的管道

    我试图让执行子进程中的 STDOUT STDERR 通过 Perl 中的管道返回到父进程 我见过的最接近我想做的事情是 http forums devshed com perl programming 6 exec and redirect
  • 强制 protobuf-net 忽略 IEnumerable/ICollection 接口

    如何让 protobuf net v2 忽略我的类实现 ICollection IEnumerable 等的事实 对于这个特定场景 我只希望序列化标记为 ProtoMember 的字段 我目前正在从使用 protobuf net v1 转换
  • perl - 子进程向父进程发送信号

    我编写了以下代码来测试孩子和父母之间的信号传递 理想情况下 当子进程向父进程发出 SIGINT 时 父进程应该在新的迭代中返回并等待用户输入 我在 perl 5 8 中观察到了这一点 但在 perl 5 6 1 我被要求使用 中 父级实际上
  • 非 Web 项目的 XML 序列化程序集

    我正在尝试解决 VS 2010 VB NET 和 C 中自动生成序列化程序集的众所周知的问题 项目设置中的 生成序列化程序集 选项对于非 Web 项目没有任何作用 请参阅http blog devstone com aaron archiv
  • Crypt::OpenPGP Symkey 解密失败:无效的密钥 ID

    我遇到问题在哪里地穴 OpenPGP https metacpan org module Crypt 3a 3aOpenPGP无法解密 GPG 编码的消息 看来我是不是第一个 http www perlmonks org node id 9
  • 使用 System.Text.Json.Serialization.JsonConverter 解析 JSON 序列化过程中复杂类型的循环引用

    有一个复杂类型引用相同类型的对象 有时是同一对象 public class User public string Name get set public int Age get set public User Reference get s
  • 对象 xml 反序列化问题?

    我的对象具有父子关系 每个子对象都有一个Parent指向其容器的属性 当这个对象在应用程序中创建时 它就被设置了 因此没有问题 此 Parent 属性标记有 XmlIgnore 属性 因为它需要设置为其运行时父实例 那么 在对象反序列化后初
  • 如何从 Perl 中的文本文件中提取/解析表格数据?

    我正在寻找类似的东西HTML 表格提取 http search cpan org dist HTML TableExtract 只是不适用于 HTML 输入 而是适用于包含采用缩进和间距格式化的 表格 的纯文本输入 数据可能如下所示 Her
  • 序列化匿名类型

    我想将匿名类型变量转换为 byte 我该怎么做 我尝试过的 byte result var my new Test a1 Value 0 BinaryFormatter bf new BinaryFormatter using Memory
  • WCF - 将空元素转换为可为空的本机类型

    将 SOAP 字段元素留空会导致本机类型出现强制转换错误 遗憾的是 由于客户端限制 无法使用 xsi nil true 将 WCF 协定本机类型标记为 nullable 似乎不足以阻止将以下错误返回给客户端 字符串 不是有效的布尔值 在 S
  • WPF:BinaryFormatter 可以序列化 FlowDocument 实例吗?

    我喜欢使用binaryformatter来序列化流文档 但这是例外 Serializable public class BinFlow public FlowDocument my get set BinFlow myBF new BinF
  • readRDS() 加载额外的包

    什么情况下会出现readRDS R 中的函数尝试加载包 命名空间 我很惊讶地在新的 R 会话中看到以下内容 gt loadedNamespaces 1 base datasets graphics grDevices methods sta
  • 将 json 反序列化为对象:包装类解决方法

    这是我的 json accessType Grant spaces spaceId 5c209ba0 e24d 450d 8f23 44a99e6ae415 privilegeId db7cd037 6503 4dbf 8566 2cca4

随机推荐

  • 反应选择-为下拉菜单和控制显示不同的文本/标签?

    在我的反应选择下拉列表中 标签有数百个字符长 在控制芯片中 我想显示下拉菜单中内容的较短版本 这可能吗 编辑 我想设置芯片的文本 而不是像素宽度 解决方案1 使用多值时可以自定义控制芯片的样式Select与道具styles就像下面的例子 c
  • 我应该如何在 Pyside6 应用程序中使用 Material Design?

    我的 pyside 6 应用程序中有以下代码 import sys os from PySide6 QtGui import QGuiApplication from PySide6 QtQml import QQmlApplication
  • HTML5 微数据:跨越内容?

    我读过了HTML5 规范 http www w3 org TR 2014 REC html5 20141028 single page html 微观数据规范 http www w3 org TR 2013 NOTE microdata 2
  • AngularJS - 多个指令实例多次调用 XHR

    我有一个 Angularjs 指令 ExampleDirective 它具有控制器 ExampleController 控制器定义了两个 Promise 对象 其中每个 Promise 对象发出 Http GET 请求并返回响应 在指令中
  • 如何使用 terraform 输出作为 Azure DevOps 管道中的变量

    我试图将使用 Azure DevOps 的 terraform 部署生成的 databricks 工作区名称作为变量传递到另一个步骤 但不知道该怎么做 所以我在我的output tf中定义了输出 output workspace name
  • 当文件打开后被删除时,Python 如何读取该文件

    我很难理解 Python 在删除文件后如何读取文件的概念open编辑 这是代码 gt gt gt import os gt gt gt os system cat foo txt Hello world 0 gt gt gt f lt io
  • 部分类与扩展方法

    我没有太多使用这两种方法来扩展类或针对类创建扩展方法的经验 通过查看其他人的工作 我在这里有一个问题 我看到人们在项目中使用分部类来扩展实体类 同时 在同一个项目中 还有另一个文件夹 其中包含很多实体类的扩展方法 这样做对吗 我的意思是这两
  • 我可以向 SKSpriteNode 添加边框吗,类似于 UIView?

    我感兴趣如果SKSpriteNode可以模仿一个人的行为UIView我可以在哪里指定边框和角半径 self view layer borderColor UIColor lightGrayColor CGColor self view la
  • Excel 中是否有一个类似的命令,其执行与 MATLAB 中的“floor”命令相同的功能[重复]

    这个问题在这里已经有答案了 MATLAB 中的 floor 命令定义为 向负无穷大舍入 Floor X 将 X 的元素四舍五入为最接近的整数 趋向于负无穷大 Excel 中是否有类似的命令 或者有人知道如何在 Excel 中执行相同的操作
  • C DLL 到 Python 回调

    我有一个 Visual C DLL 我在 DLL 中导出了 SetCallback 函数指针 我使用此函数从 python2 7 脚本设置回调函数 我遵循 Python 文档中给出的内容 from ctypes import def myp
  • 如何在 vue-cli 中禁用 ESLint?

    我该如何禁用ESlint在生成的项目中vue cli preLoaders test vue loader eslint include projectRoot exclude node modules test js loader esl
  • Google Sheets 查询图像从查询结果中显示

    当图像从查询中出来时 我不知道如何在 gsheet 的单元格中显示图像 我尝试过各种形式的数组公式和查询组合 但没有任何结果 希望有任何帮助 尝试过这个 A4 A21 是图像 URL ARRAYFORMULA 查询 B4 B21 图像 A4
  • Objective-C 中的美元符号是什么意思?

    CAGradientLayer grad CAGradientLayer layer grad colors array ColRGBA2 1 0 0 1 ColRGBA2 0 1 0 1 ColRGBA2 0 0 1 1 ColRGBA2
  • 如何让 axios 使用 AWS ACM 公共证书?

    我很惊讶地发现 在使用 axios 和 node fetch 时 AWS ACM 颁发的公共证书会触发 无法验证第一个证书 错误 但是 当我从命令行使用curl 时 我没有收到错误 所以我的问题是 为什么节点会有这样的行为 Curl 似乎可
  • 对小文本进行有效搜索

    我有许多小文本 假设大约 500 个单词 和两个数据库 每个数据库大约有 10 000 个条目 关键字 我现在想要处理每个文本并找出文本中包含哪些关键字 保存在两个数据库中的关键字 你们中有人有关于如何有效地做到这一点的好方法吗 我想在搜索
  • 使用正则表达式的缺点

    最近 我的经理建议我不要过度依赖正则表达式 因为它有很多缺点 当我尝试了解更多信息时 我听说它存在诸如正则表达式之类的问题 因为某些对象即使在使用后仍会继续挂在字符串引用上 从而导致内存泄漏 NET RegEx 内存泄漏 调查 https
  • NgRx 和 localStorage 的组合

    我对 NGRX 和状态管理的概念有点陌生 因为我来自后端开发 每当我看到和听到状态管理这个术语时 我脑海中浮现的就是 CQRS 嗯 互联网上的一些文章说它是以此为模式的 我的问题是 在我的角度应用程序中 我可以做类似的事情 从后端获取数据然
  • 减少频繁重新部署(上传)到远程服务器的战争规模

    在开发过程中 我需要经常更新我的 Web 应用程序源代码并将更新后的 war 部署到远程 Tomcat 服务器 在我的连接上上传大型战争 25MB 需要太长时间 大约 30 分钟 效率非常低 有什么办法可以减少战争规模吗 我的项目中有很多外
  • CSS:浮动时忽略div高度

    I m trying to display some pictures All of them have the same width but different height I m trying to do something like
  • 在不同 Perl 版本下运行的程序之间传递对象

    使用从 perl5 6 pl 到 perl5 24 pl 的不同 perl 版本将对象作为输入参数传递时遇到问题 无法从函数 from 5 24 获取返回值 下面提供了有问题的代码 使用windows平台 如何解决这个问题 SharedBe