Implement a node list in Perl

I wrote the following module, but not sure how to access the "last" and "head" nodes. Besides storing the address of the next node in "{nextNode}" in the previous node.

I try to keep a reference to the class when it is stored, but later it complains: "Not a HASH link in List.pm"; that I understand why, but I'm not sure how the syntax will be.

If I de-link $ head and $ last ($$ last → {nextNode} = \ $ class), then I think it uses the actual name of my class; A list, not the previous object, as I want.

package List; my $head = undef; my $last = undef; sub new { my $class = shift; # init the head of the list if ($head == undef) { $head = \$class; print "updated head to:$head", "\n"; } $last = \$class; $last->{nextNode} = \$class; # update previous node to point on this new one print "updated last to:$last", "\n"; my $self = {}; $self->{value} = shift; $self->{nextNode} = ""; # reset next to nothing since this node is last return bless $self, $class; } 

Thanks guys,

+4
source share
3 answers

You should store $self everywhere, not the \$class . Storing a $ class is simply storing the class name, not the object itself.

Also, for $self->{nextNode} I would save undef instead of an empty string. Or better yet, just don't create it at all and use exists to check if it exists .

+6
source

You already think about it. If you use an array for your list instead of a hash, you do not need to worry about the head and the latter. The head of the array is $array[0] , and the last element is $array[-1] . Simple and convenient.

Here's a quick definition of a standard class for defining a list. I just defined a constructor (new routine) and one method (list).

 package Local::List; sub new { my $class = shift; my $self = {}; bless $self, $class; $self->list([]); } sub list { my $self = shift; my $list_ref = shift; if (ref $list_ref ne "ARRAY) { return; } if (defined $list_ref) { $self->{LIST} = $list_ref; } if wantarray { return $self->{LIST}; } } 

First: use the same standard names that everyone else uses. Use new for constructor. When I try to look at the documentation on how to use your class, I can find the word new and find out how I create the class object. Also use the variable names $class and $self . This is what everyone else is doing, so it’s easy to understand what is happening.

Note that in my new routine, the first element passed is the name of the class, and the first element passed to my other routines is a reference to my class object (i.e. $self ). This is probably the most difficult to understand classes.

Pay attention to new , I immediately create my $self and bless it. That way, I can call my other routines (my methods) to do the tuning for me. Thus, my constructor does not know how my class is structured. This has many advantages:

  • When (not if) I change my class, I do not need to change the constructor.
  • My constructor is always synchronized with all my methods.
  • I do not need to know how a class object is structured when I start defining a class. I can start writing my class without worrying about all these dirty details about how it will work.

Note that the list routine (or method) can either set the list or return a list. This is much simpler if you use the same routine to set or get a value. Also, in method routines, use null return when the method function returns an error. Otherwise, always return something. This makes it easy to check if the method worked or not.

Take a look at some of the other methods that you probably want. Let all four standard list functions:

  • push
  • pop
  • shift
  • unshift

Here is an example:

 sub push { my $self = shift; my $member = shift; if (not defined $member) { return; } my $list_ref = $self->list; my $return = push @{ $list_ref }, $member; $self->list($list_ref); return $return; } 

Wow, that’s easy. Note that pop doesn't know what my class looks like. He used the list method to get a link to a list. He then used the built-in push method to insert the item into the list. I store this return value, and this is what I will return. I'm not even sure what push returns. All I know is that push returns something if it succeeds. (Yes, I know that it returns the number of elements in the list).

The other three functions are more or less the same. Here are a few more:

  • current
  • splicing
  • Following
  • previous
  • head
  • the last

All you have to do for the current is to keep the current value. Use the same function to set and get the value. Note that my list method or my push method or my new constructor knows or cares about how you store it. Do not use our next and previous methods. All they need to do is increase or decrease the value of current and save it using the routine of the current method:

 sub next { my $self = shift my @list = $self->list; #Returns a list; my $current = $self->current; my $list_size = $#list; if ($current eq $list_size) { return; #Can't return a value after the end of the list! } $current++; #Increment the value; my $value = $list[$current]; #I'll return this $self->current($current) #Store the new current return $value; } 

And now, based on your question: getting the last and main values ​​of the list. Here is the last

 sub last { my $self = shift; my $list_ref = $self->list; return ${ $list_ref }[-1]; } 

And a quick copy and paste will give me a head:

 sub head { my $self = shift; my $list_ref = $self->list; return ${ $list_ref }[0]; } 

What is it! Everything that bothered you was in vain.

Sorry for the long post. I just wanted to emphasize that object-oriented programming in Perl is not so difficult if you follow a few simple guidelines.

(Simple? How about use Moose; No, I just said!) .; -)

+3
source

I just want to publish my final working version for the record and your feedback / comments. Thanks again!!

 package List; my $head = undef; my $last = undef; sub new { my ($class, $val) = @_; my $self = {}; # init the head of the list if (!defined $head) { $head = $self; print "updated the head of the list ($head)" . "\n"; } else { $last->{nextNode} = $self; # update previous node to point on this new one } $last = $self; # this object is now the last one $self->{value} = $val; # store the value $self->{nextNode} = undef; # reset next to nothing since this node is last return bless $self, $class; } sub setVal { my ($class, $val) = @_; $class->{value} = $val; } sub getVal { my $class = shift; print $class->{value}; } sub getNext { my $class = shift; return $class->{nextNode}; } # return true if this is the last node, otherwise false. sub isLast { my $class = shift; return 1 if !defined $class->{nextNode}; return 0; } sub getLast { return $last; } sub getHead { return $head; } # looping through all the list and printing the values sub showList { my $node = $head; # set temp node to the head while ( !$node->isLast() ) { print $node->{value} . "\n"; $node = $node->{nextNode}; } # printing last value. (should be defined but I check it just in case) print $node->{value} . " (last)\n" if defined $node->{value}; } 1; 

Script:

 my $n0 = new List(4); my $n1 = new List(8); my $n2 = new List(9); my $n3 = new List(3); my $n4 = new List(1); my $n5 = new List(0); my $n6 = new List(5); print "\nShow list: \n"; $n2->showList(); # any object will print the list 
0
source

Source: https://habr.com/ru/post/1442311/


All Articles