【问题标题】:Procedural and object oriented interface in Perl/XSPerl/XS 中的过程和面向对象的接口
【发布时间】:2014-10-23 07:58:29
【问题描述】:

我目前正在编写我的第一个 XS 模块(只是 C 数学库的一个包装器)并取得了不错的成功。最大的问题是文档很难理解和/或不完整。

我已经成功地在 XS 中编写了一个构造函数,并从库中实现了一些函数作为方法调用。效果很好。

现在我也想实现一个过程接口。出于这个原因,我需要知道它是否是一个方法调用。如果它是一个方法调用,则用函数计算的数字存储在实例中,如果它是对函数的过程调用,它的第一个参数就是一个数字。 这是余弦函数的当前代码:

double
cos(...)
    CODE:
        SV *arg = newSVsv(ST(0));
        if (sv_isobject(arg)) {
            HV *self_hv = MUTABLE_HV(SvRV(arg));
            SV **callback_ptr = hv_fetchs(self_hv, "Number", 0);
            SV *zahl = *callback_ptr;
        }
        else {
            SV *zahl = newSVnv(arg);
        }

        double x = SvNV(zahl);
        RETVAL = cos(x);
    OUTPUT:
        RETVAL

【问题讨论】:

  • 你好像忘了问一个问题。你甚至没有暗示一个问题。你想要什么?
  • 注意:您使用ST(0) 而不检查您有多少参数。
  • 我的问题是:当我将它作为没有 if 和整个 else 块的方法调用时,它可以工作。所以我想我的问题出在 if 条件的某个地方。注意:代码甚至没有编译,它在分配双精度的行上抛出一个错误(第一次使用但没有声明,所以我假设 if 条件一定是这里的问题
  • 首先,你没有提到有错误。现在,你不提它是什么?我们无法读懂你的想法(或你的屏幕)!

标签: perl xs


【解决方案1】:

一般来说,编写旨在被称为方法或函数的 subs 是一个坏主意。有一两个众所周知的模块可以做到这一点(想到 CGI.pm),但在大多数情况下,这会让最终用户感到困惑,并且不必要地使您自己的代码复杂化。没有人会为此感谢你。选择一种风格并坚持下去。

假设您选择坚持使用 OO 编程。然后,一旦您的模块工作并经过测试,您就可以编写第二个模块,提供可导出的功能而不是 OO 接口。第二个模块可能可以用普通的旧 Perl 编写,只是充当 OO 模块的包装器。

例如,使用纯 Perl(而不是 XS)来提高可读性:

use v5.14;

package MyStuff::Maths::OO {
   use Class::Tiny qw(number);
   sub cosine {
      my $self   = shift;
      my $number = $self->number;
      ...;
      return $cosine;
   }
}

package MyStuff::Maths::Functional {
   use Exporter::Shiny qw(cosine);
   sub cosine {
      my $obj = ref($_[0]) ? $_[0] : MyStuff::Maths::OO->new(number => $_[0]);
      return $obj->cosine;
   }
}

现在最终用户可以选择像这样使用您的 OO 界面:

use v5.14;
use MyStuff::Maths::OO;

my $obj = MyStuff::Maths::OO->new(number => 0.5);
say $obj->cosine;

或者使用函数式接口:

use v5.14;
use MyStuff::Maths::Functional -all;

say cosine(0.5);

【讨论】:

  • 我明白你的意思。一般来说,我也会这样做。但我开始研究这个特殊的东西来了解 XS。所以用普通 Perl 编写包装器并不是重点。
  • @user2875983,实际上,它比你想象的要多。如果您想学习使用 XS,那么学习在 Perl 方面应该做什么和不应该做什么是有用的一课。
  • @user2875983,如果您愿意,没有什么可以阻止您在 XS 中编写包装器。除了速度增益之外,这样做几乎没有什么优势。我的主要观点是,将这两个接口分成两个模块将节省您的理智,以及您的最终用户的理智。无论您是编写 XS 还是纯 Perl,这都是一样的。
【解决方案2】:

在我的情况下,这是一个简单的问题,我根本没有看到它。 if-else-statement 中的 SV *zahl 声明是问题所在。 if 之前的预声明是解决问题的关键。

但我同意 tobyinks 的解决方案,用于其他人使用或在某处发布的模块。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多