2010-08-04 5 views
12

내 목표는 다음과 같이 $obj을 사용할 수 있도록하는 것입니다Perl : 즉석에서 객체를 만드는 방법은 무엇입니까?

print $obj->hello() . $obj->{foo}; 

그리고 어쩌면이 같은 것을 를 사용하여 객체를 인라인으로 만들 싶습니다 : 내가하려고 할 때

my $obj = (
    foo => 1, 
    hello => sub { return 'world' } 
); 

하지만, $obj을 개체로 사용하려면 $ obj에게 축복이되지 않았다는 오류 메시지가 표시됩니다.. 내가 객체로 사용할 수 있도록 해시를 축복하는 데 사용할 수있는 기본 클래스 (예 : stdClass)가 있습니까? 자바 스크립트를 알고있는 사람들을 위해


, 나는 다음을 수행하려고하지만, 펄 :

# JS CODE BELOW 
var obj = { foo: 1, hello: function() { return 'world' } }; 
echo obj.hello() + obj.foo; 
+0

펄 방법은 해시 필드 아니다 - 이것은 자바되지 않습니다. – Ether

+0

자바 스크립트가 자바가 아닙니다. – cjm

답변

14

Perl은 약간의 도움이 필요합니다. 해시에 저장된 코드 참조를 "메소드"로 간주하지 않기 때문입니다. 메소드는 패키지 기호 테이블에 항목으로 구현됩니다.Perl은 클래스 지향보다 자랑스럽게 더 객체 지향 (on 개별 개체)입니다.

이 기능을 수행하려면이 방법으로 참조를 매핑 한 클래스를 만들어야합니다. 기호 테이블의 메서드를 가져 오는 방법은 AUTOLOAD 메서드입니다. 패키지에 AUTOLOAD 서브 루틴이 포함되어있는 경우, 상속 체인에서 Perl이 찾을 수없는 축복 된 객체를 호출하면 AUTOLOAD을 호출하고 패키지 범위 (our) 변수 $AUTOLOAD의 전체 이름을 포함하게됩니다. 기능.

정규화 된 하위 이름의 마지막 노드 (마지막 '::'다음)를 가져 와서 호출되는 메소드의 이름을 가져옵니다. 해당 위치에 코드 참조자가 있는지 살펴보고, 코드 판독기가있는 경우 반환 할 수 있습니다.

package AutoObject; 

use strict; 
use warnings; 
use Carp; 
use Params::Util qw<_CODE>; 
our $AUTOLOAD; 

sub AUTOLOAD { 
    my $method_name = substr($AUTOLOAD, index($AUTOLOAD, '::') + 2); 
    my ($self) = @_; 
    my $meth  = _CODE($self->{$method_name}); 
    unless ($meth) { 
     Carp::croak("object does not support method='$method_name'!"); 
    } 
    goto &$meth; 
} 


1; 

그런 다음 해당 클래스로 객체를 축복합니다 :

package main; 

my $obj 
    = bless { foo => 1 
     , hello => sub { return 'world' } 
     }, 'AutoObject'; 

print $obj->hello(); 

일반적으로, AUTOLOAD 하위에있는 I "시멘트"동작을. 즉, 다음에 AUTOLOAD을 피하기 위해 패키지 기호 테이블에 항목을 만듭니다. 그러나 이것은 보통 합리적으로 정의 된 클래스 동작을위한 것입니다.

또한 선언 된 각 객체에 대해 패키지를 만드는 QuickClass을 디자인했으나 Class::MOP으로 더 잘 수행 될 수있는 많은 논쟁 테이블을 포함합니다.


에릭 스트롬의 제안에 따라 다음 코드를 AutoObject 패키지에 추가 할 수 있습니다. import sub는 누군가 use -d AutoObject (매개 변수 'object')으로 언제든지 호출됩니다.

use AutoObject qw<object>; 

그리고 표현은 다음과 같습니다 : 당신은이 "개체 리터럴"만들고 싶었 때

# Definition: 
sub object ($) { return bless $_[0], __PACKAGE__; }; 

sub import { # gets called when Perl reads 'use AutoObject;' 
    shift; # my name 
    return unless $_[0] eq 'object'; # object is it's only export 
    use Symbol; 
    *{ Symbol::qualify_to_reference('object', scalar caller()) } 
     = \&object 
     ; 
} 

그리고, 당신은 할 수

object { foo => 1, hello => sub { return 'world' } }; 

당신도 할 수 :

object { name => 'World' 
     , hello => sub { return "Hello, $_[0]->{name}"; } 
     }->hello() 
     ; 

그리고 "개체 리터럴 "표현. 아마 모듈은 Object::Literal이라고 더 좋을 것입니다.

+0

이것은 실제로 유용한 트릭입니다. 필자가 Perl에서 OOP를 사용했다면 이것을 잘 사용할 수 있습니다. –

+0

'sub object {bless $ _ [0] => 'AutoObject'}'그리고'my $ obj = object {...};'서브 클래스에 축복을 숨겨서 호출 코드를 좀 더 깔끔하게 만들 수 있습니다. –

+0

@Eric Strom : 그건 좋은 말이야. 하지만 여기 내 생각 : 자바 스크립트 관용구는 기본적으로 "개체 리터럴"입니다. Perl에서 "객체 리터럴"은 (종종) '축복 {...}', 'MyClass'입니다. * 물론 *, '축복'은 단지 기능 일 뿐이므로 '객체 {...}'가 더 나은 리터럴이 될 이유가 없습니다. 내 코드를 바꿀거야. – Axeman

2

$obj 스칼라가 될 것입니다, 그래서 같은 스칼라이어야에 당신은 지정 어떤 잘. 당신은

my %obj = (foo => 1, hello => sub { return 'world' }); 

또는

my $obj = { foo => 1, hello => sub { return 'world' }}; 

후자는, 중괄호와 함께, 해시 참조 생성 말할 수 중 (스칼라, 그래서 그것은 $obj로 갈 수있다). 하지만 해시 참조 내부의 내용을 보려면 화살표 연산자를 사용해야합니다. $obj->{foo} 또는 &{$obj->{hello}}과 같은 것입니다.

해시 목록 등이 필요한 경우가 아니면 일반적으로 첫 번째 방법을 사용하는 것이 좋습니다.

어쨌든 $obj->hello()을 말할 수 없습니다. Perl은 OOP의 고유 한 맛을 위해이 구문을 사용합니다.이 구문은 참조 패키지가 blesshello으로 분리되어 있습니다. 좋아요 :

package example; 
sub new {} { my $result = {}; return bless $result, 'example' } 
sub hello { return 'world' } 

package main; 
my $obj = example->new(); 

당신이 볼 수있는 것처럼, 당신이 부를 수있는 방법은 이미 정의되어 있습니다. 더 많은 것을 추가하는 것은 쉽지 않습니다. 그런 일을하는 데 사용할 수있는 마법 방법이 있지만 실제로는 가치가 없습니다. &{$obj{hello}} (또는 참조 용으로 &{$obj->{hello}})은 Javascript와 같은 Perl 작업을 시도하는 것보다 노력이 적습니다.

+0

글쎄요, 이것은 오늘 나머지 시간 동안 자료를 읽게 해줍니다. – Tom

0

Perl의 메소드는 Python 에서처럼 객체의 속성이 아닙니다. 메소드는 객체와 연관된 패키지의 일반 일반 함수 함수입니다. 자체 참조에 대한 추가 인수를 취하는 일반 함수.

동적으로 함수를 메서드로 만들 수 없습니다.()

1. An object is simply a reference that happens to know which class it 
     belongs to. 

    2. A class is simply a package that happens to provide methods to deal 
     with object references. 

    3. A method is simply a subroutine that expects an object reference 
     (or a package name, for class methods) as the first argument. 

아, 그리고 축복이 기준과 패키지 사이의 연결을 설정하는 방법입니다 : 여기

는 perldoc을의 perlobj에서 인용이다.

+0

"당신은 동적으로 함수를 메소드로 생성 할 수 없습니다."라고 말하면서 확실하게 알지 못합니다. * 함수를 동적으로 생성하여 소포. 많은 CPAN 모듈이이를 수행합니다. 비교적 간단한 예제처럼 Getopt :: Long :: Descriptive를 참조하십시오. 사용자가 요청한 각 옵션 구문 분석기에 대해 새 클래스 이름을 생성합니다. 이 패키지에는 사용자가 정의한 각 명령 행 옵션에 대한 getter가 설치됩니다. – FMc

+0

나는 그가 원하는 방식으로 메서드를 추가 할 수 없다는 것을 의미합니다. 동적 함수 삽입은 이것보다 훨씬 더 까다 롭습니다 ("엄격한 ref; * {"$ package \ :: function "} = sub {...};", 누구든지?) 가볍게 착수해서는 안됩니다. – Arkadiy

1

개체를 생성하는 함수가 무엇이든간에 메서드 호출을 사용하려면 개체에 bless을 호출해야합니다. 예를 들어

:

package MyClass; 

sub new 
{ 
    my $obj = { 
    foo => 1 
    }; 

    return bless($obj, "MyClass"); 
} 

sub hello 
{ 
    my $self = shift; 
    # Do stuff, including shifting off other arguments if needed 
} 

package main; 
my $obj = MyClass::new(); 

print "Foo: " . $obj->{foo} . "\n"; 
$obj->hello(); 

편집 : 당신이 당신의 개체에 대한 동적 기능을 제공하는 서브 루틴 참조를 사용 할 수있게하려면 ...

my $obj = MyClass::new(); # or whatever 
$obj->{hello}->(@myArguments); 

약간 복잡하지만 :

my $obj = { 
    foo => 1, 
    hello => sub { print "Hello\n"; }, 
} 

당신은 다음과 같이 그것을 호출 할 수

첫째, 당신은 너무 같은 (이 해시 생성자의 예에서) 코드의 참조를 만들 수 있습니다 공장. (당신은 두 번째 화살표 필요하지 않을 수도 있습니다,하지만 난 모르겠어요.)

2

그것은 Perl로 약간 다르게 철자 :

my $obj = { foo => 1, hello => sub { return "world" } }; 
print $obj->{hello}() . $obj->{foo}; 

을하지만 코드는 어색하다. 참조에 대해 축복을받지 못했다는 경고는 객체가 the way Perl expects에 구현되어 있지 않다는 것을 알려줍니다. bless 연산자는 메서드 검색을 시작할 패키지에 개체를 표시합니다.

문제 도메인 측면에서 원하는 것을 알려주고 Perl에서 자연스럽게 접근 할 수있는 방법을 제안 할 수 있습니다.

4

더 많은 Perlish 접근법은 객체의 원하는 메소드에 대한 별도의 네임 스페이스를 만들고 객체에 대해 해당 메소드를 사용할 수 있도록 객체를 생성하는 것입니다. 이 작업을 수행하는 코드는 여전히 숙제가 될 수 있습니다. 당신이 $obj->{hello}->() 대신 $obj->hello()을 쓸 의향이 있다면 gbacon이 있듯이

my $obj = bless { foo => 1 }, "bar"; 
sub bar::hello { return 'world' }; 

, 당신은 축복 작업을 건너 뛸 수 있습니다.

my $obj = { foo => 1, hello => sub { return 'world' } }; 
0

perltoot 매뉴얼 페이지에서 설명한대로 Class :: Struct를 사용하는 것이 좋습니다.

그 분야 특정의 개체를 가진 것으로 "클래스를 선언"그것이 무엇을하는 것은 당신이 할 수있는 방법을 제공하는 것이다 "

대신 문서를 의역, 그것은 이것이 잘 작동하는 방법을 설명 된대로 내가 그것을 인용하자 이 작업을 수행하는 함수는 구조체 또는 레코드가 Perl의 기본 유형이 아니기 때문에 레코드와 유사한 데이터 객체를 제공 할 클래스를 만들 때마다 직접 작성해야합니다. new() 메서드를 정의하고 각 레코드 필드에 대해 별도의 데이터 액세스 메서드를 정의하면 Class :: Struct :: struct() 함수가이 지루함을 빨리 해결할 수 있습니다. " 아직도 문서에서 인용

를 구현하는 방법에 대한 예 방법 :

use Class::Struct qw(struct); 
use Jobbie; # user-defined; see below 
struct 'Fred' => { 
    one  => '$', 
    many  => '@', 
    profession => 'Jobbie', # does not call Jobbie->new() 
}; 
$ob = Fred->new(profession => Jobbie->new()); 
$ob->one("hmmmm"); 
$ob->many(0, "here"); 
$ob->many(1, "you"); 
$ob->many(2, "go"); 
print "Just set: ", $ob->many(2), "\n"; 
$ob->profession->salary(10_000); 
관련 문제