【问题标题】:What is wrong with this Perl subroutine?这个 Perl 子程序有什么问题?
【发布时间】:2017-04-21 23:04:33
【问题描述】:

我正在尝试实现一个计算输入字符串的 d 邻居的子例程。这是planted motif search 实现的一部分,但我的问题更为笼统。代码如下:

#subroutine for generating d-neighbors
sub generate_d_neighbors{
    # $sequence is the sequence to generate d-neighbors from
    # $HD is the Hamming Distance
    my ($sequence, $HD) = @_;

    for(my $i = 0; $i=$HD; $i++){
        my @l = ['A', 'C', 'T', 'G'];
        my @t = splice(@l,$sequence[$i]);  
       #TODO
    }
}

错误发生在最后一行,说:

Global symbol "@sequence" requires explicit package name (did you forget to declare "my @sequence"?

据我了解,Perl 不像 Java 中那样采用 subroutine(param1, param2) 形式的参数,但为什么 $sequence 没有被识别为已经初始化?

【问题讨论】:

  • 你使用了$sequence[0],但是你还没有声明@sequence。在 Perl 中,$sequence@sequence 是两个不同的变量
  • 另外,分配$i=$HD 可能不是您的意思。通常会进行某种比较。
  • $sequence[0] 是您访问名为@sequence 的数组元素的方式。 Perl 正确地指出它对名为@sequence 的变量一无所知。您可能传递了一个数组 reference,应该使用取消引用箭头访问它:$sequence->[0]

标签: perl subroutine


【解决方案1】:

您的代码存在一些问题:

sub generate_d_neighbors{
    my ($sequence, $HD) = @_;

    for(my $i = 0; $i=$HD; $i++){
        my @l = ['A', 'C', 'T', 'G'];
        my @t = splice(@l,$sequence[$i]);  
    }
}

首先我们来看看

    for(my $i = 0; $i=$HD; $i++){

假设$HD 不为零,则此循环将永远不会终止,因为条件永远不会为假。如果您希望$i 的范围从0$HD,则将语句写为for my $i (0 .. $HD) 会更好。

第二,你有

        my @t = splice(@l,$sequence[$i]);  

您似乎假设有一个数组 @sequence 并且您正在尝试访问它的第一个元素。但是,$sequence 是对数组的引用。因此,您应该使用

$sequence->[$i]

第三(感谢@Ikegami),你有

        my @l = ['A', 'C', 'T', 'G'];

for-loop 的主体中。然后@l 将包含一个元素,一个对包含元素'A''C''T''G' 的匿名数组的引用。相反,使用:

my @l = qw(A C T G);

我不确定你想用splice(@l, $sequence->[$i]) 实现什么,但最好写成:

 my @t = @l[0 .. ($sequence->[$i] - 1)];  

实际上,您可以将这两个分配简化为:

 my @t = qw(A C T G)[0 .. ($sequence->[$i] - 1)];

【讨论】:

  • @ikegami 感谢您指出这些。我不确定在原始 sn-p 中使用 splice 是否是 OP 的意图,但从表面上看,我试图采纳您的反馈。
  • 拼接线用于移除当前位置的底座。例如,$sequence = "ATG";$HD = 1; 在位置 0,我想删除 A,只剩下 C T G。同样对于位置 1,删除 T 并留下 A C G 等。
  • 那么,$sequence 是简单的标量还是对数组的引用?
  • @SinanÜnür 对数组的引用,是的。这样我就可以在generate_d_neighbors 中输入一个序列(数组),并将序列中每个位置的字母替换为其他 3 个可能的字母。
  • splice(@x, 2) 从索引 2 开始删除所有内容。看来你需要grep
【解决方案2】:

它看起来像你想要的

substring($sequence, 0, 1)

而不是

$sequence[0].

在 Perl 中,字符串是第一类变量,而不是数组类型。

或者你想要splice(@l, $sequence->[0])

【讨论】:

  • 糟糕,刚刚编辑了问题。意思是 $i 并且没有 0
【解决方案3】:

这个列表赋值语法:

my (@sequence, $HD) = @_;

没有做你希望它做的事情(把最后一个参数放在$HD 中,其余的放在@sequence 中)。数组总是接受它可以接受的所有参数,后面的任何参数都没有。

对于只有一个数组的情况,可以颠倒顺序:

my ($HD, @sequence) = @_;

然后你在调用者中做出相应的改变。

要更一般地解决问题,请使用参考:

my ($sequence, $HD) = @_;

并像这样调用子:

generate_d_neighbors(\@foo, $bar);

或者这个:

# Note the brackets, which make an array reference, unlike parentheses
# which would result in a flat list.
generate_d_neighbors([...], 42);

如果你使用原型:

sub generate_d_neighbors (\@$)

然后调用者可以说

generate_d_neighbors(@foo, $bar);

并且@foo 自动成为引用,就好像它曾经是\@foo

如果您使用任何基于引用的解决方案,则必须按照以下规则更改函数主体以使用 $sequence 而不是 @sequence

  1. @sequence 更改为@$sequence
  2. $#sequence 更改为$#$sequence
  3. $sequence[...] 更改为$sequence->[...]
  4. @sequence[...] 更改为@$sequence[...](但请确保您确实打算使用数组切片...如果您是perl 新手,您可能不是故意的,应该改用$sequence[...]

【讨论】:

    猜你喜欢
    • 2021-07-25
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多