문제

클래스의 "새"메소드 내에서 Perl에서 "축복"키워드를 사용한다는 것을 이해합니다.

sub new {
    my $self = bless { };
    return $self;
}    

그러나 그 해시 참조에 대해 "축복"이 정확히 무엇을하고 있습니까?

도움이 되었습니까?

해결책

일반적으로 bless 객체를 클래스와 연관시킵니다.

package MyClass;
my $object = { };
bless $object, "MyClass";

이제 메소드를 호출 할 때 $object, Perl은 메소드를 검색 할 패키지를 알고 있습니다.

예제에서와 같이 두 번째 인수가 생략되면 현재 패키지/클래스가 사용됩니다.

명확성을 위해 예제는 다음과 같이 작성 될 수 있습니다.

sub new { 
  my $class = shift; 
  my $self = { }; 
  bless $self, $class; 
} 

편집 : 참조 kixx좋은 대답 조금 더 자세하게.

다른 팁

bless 참조를 패키지와 연관시킵니다.

참조가 무엇이든, 해시 (가장 일반적인 경우), 배열 (일반적이지 않음), 스칼라 (일반적으로 이것은 내부 객체), 정규 표현, 서브 루틴 또는 타이프 로브 (책 참조) 객체 지향적 Perl : Damian Conway의 개념 및 프로그래밍 기술에 대한 포괄적 인 안내서 유용한 예제의 경우) 또는 파일 또는 디렉토리 핸들에 대한 참조 (최소한의 경우).

그 효과 bless-ing은 축복받은 참조에 특수 구문을 적용 할 수 있다는 것입니다.

예를 들어, 축복받은 참조가 $obj (관련 bless 그런 다음 패키지 "클래스") $obj->foo(@args) 서브 루틴을 호출합니다 foo 그리고 첫 번째 인수로 참조를 통과하십시오 $obj 나머지 논쟁이 뒤 따른다 (@args). 서브 루틴은 패키지 "클래스"로 정의되어야합니다. 서브 루틴이없는 경우 foo 패키지 "클래스"에서 다른 패키지 목록 (배열을 찍는 것) @ISA 패키지 "클래스")에서 검색하고 첫 번째 서브 루틴이 foo 발견됩니다.

짧은 버전 : 현재 패키지 네임 스페이스에 첨부 된 해시가 표시되어 해당 패키지가 클래스 구현을 제공합니다).

이 기능은 Ref가 참조 한 엔티티에게 이제 ClassName 패키지의 개체 또는 ClassName이 생략 된 경우 현재 패키지임을 알려줍니다. 두 가지 변론 형태의 축복을 사용하는 것이 권장됩니다.

예시:

bless REF, CLASSNAME
bless REF

반환 값

이 함수는 축복받은 객체에 대한 참조를 클래스 이름으로 반환합니다.

예시:

다음은 기본 사용법을 보여주는 예제 코드이며, 객체 참조는 패키지의 클래스에 대한 참조를 축복하여 생성됩니다.

#!/usr/bin/perl

package Person;
sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
        _ssn       => shift,
    };
    # Print all the values just for clarification.
    print "First Name is $self->{_firstName}\n";
    print "Last Name is $self->{_lastName}\n";
    print "SSN is $self->{_ssn}\n";
    bless $self, $class;
    return $self;
}

여기에있는 사람들이 나를 위해 클릭하지 않았기 때문에 여기에 답을 제공 할 것입니다.

Perl의 Bless Function은 패키지 내부의 모든 기능에 대한 참조를 연관시킵니다.

왜 우리는 이것을 필요로합니까?

JavaScript에서 예제를 표현하는 것으로 시작하겠습니다.

(() => {
    'use strict';

    class Animal {
        constructor(args) {
            this.name = args.name;
            this.sound = args.sound;
        }
    }

    /* [WRONG] (global scope corruption)
     * var animal = Animal({
     *     'name': 'Jeff',
     *     'sound': 'bark'
     * }); 
     * console.log(animal.name + ', ' + animal.sound); // seems good
     * console.log(window.name); // my window's name is Jeff?
     */

    // new is important!
    var animal = new Animal(
        'name': 'Jeff',   
        'sound': 'bark'
    );

    console.log(animal.name + ', ' + animal.sound); // still fine.
    console.log(window.name); // undefined
})();

이제 클래스 구조를 제거하고 그것없이 수행 할 수 있습니다.

(() => {
    'use strict';

    var Animal = function(args) {
        this.name = args.name;
        this.sound = args.sound;
        return this; // implicit context hashmap
    };

    // the "new" causes the Animal to be unbound from global context, and 
    // rebinds it to an empty hash map before being constructed. The state is
    // now bound to animal, not the global scope.
    var animal = new Animal({
        'name': 'Jeff',
        'sound': 'bark'
    });
    console.log(animal.sound);    
})();

이 기능은 순서가없는 속성의 해시 테이블을 가져 와서 (2016 년에 동적 언어로 특정 순서로 속성을 작성할 필요가 없기 때문에) 해당 속성으로 해시 테이블을 반환하거나 새 키워드를 넣는 것을 잊어 버린 경우 IT. 전체 글로벌 컨텍스트 (예 : 브라우저 또는 Nodejs의 글로벌)를 반환합니다.

Perl에는 "이"또는 "새로운"또는 "클래스"가 없지만 여전히 비슷하게 작동하는 함수가있을 수 있습니다. 우리는 생성자 나 프로토 타입을 가지고 있지 않지만, 마음대로 새로운 동물을 만들고 개별 특성을 수정할 수 있습니다.

# self contained scope 
(sub {
    my $Animal = (sub {
        return {
            'name' => $_[0]{'name'},
            'sound' => $_[0]{'sound'}
        };
    });

    my $animal = $Animal->({
        'name' => 'Jeff',
        'sound' => 'bark'
    });

    print $animal->{sound};
})->();

이제 우리는 문제가 있습니다. 우리가 동물이 그들의 목소리가 무엇인지 인쇄하는 대신 스스로 소리를 수행하기를 원한다면 어떻게해야합니까? 즉, 우리는 동물의 소리를 인쇄하는 기능을 수행하기를 원합니다.

이를 수행하는 한 가지 방법은 각 개별 동물에게 소리를내는 방법을 가르치는 것입니다. 이것은 각 고양이가 성능에 대한 고유 한 중복 함수를 가지고 있음을 의미합니다.

# self contained scope 
(sub {
    my $Animal = (sub {
        $name = $_[0]{'name'};
        $sound = $_[0]{'sound'};

        return {
            'name' => $name,
            'sound' => $sound,
            'performSound' => sub {
                print $sound . "\n";
            }
        };
    });

    my $animal = $Animal->({
        'name' => 'Jeff',
        'sound' => 'bark'
    });

    $animal->{'performSound'}();
})->();

Performound는 동물을 구성 할 때마다 완전히 새로운 기능 객체로 배치되기 때문에 이것은 나쁩니다. 10000 마리의 동물은 100000 성능을 의미합니다. 우리는 자신의 사운드를 찾고 인쇄하는 모든 동물이 사용하는 단일 기능 성능을 원합니다.

(() => {
    'use strict';

    /* a function that creates an Animal constructor which can be used to create animals */
    var Animal = (() => {
        /* function is important, as fat arrow does not have "this" and will not be bound to Animal. */
        var InnerAnimal = function(args) {
            this.name = args.name;
            this.sound = args.sound;
        };
        /* defined once and all animals use the same single function call */
        InnerAnimal.prototype.performSound = function() {
            console.log(this.name);
        };

        return InnerAnimal;
    })();

    /* we're gonna create an animal with arguments in different order
       because we want to be edgy. */
    var animal = new Animal({
        'sound': 'bark',
        'name': 'Jeff'
    });
    animal.performSound(); // Jeff
})();

여기에는 Perl과 평행이 멈추는 곳이 있습니다.

JavaScript의 새로운 연산자는 선택 사항이 아니며, "이"내부 객체 방법은 글로벌 범위를 손상시킵니다.

(() => {
    // 'use strict'; // uncommenting this prevents corruption and raises an error instead.

    var Person = function() {
        this.name = "Sam";
    };
//    var wrong = Person(); // oops! we have overwritten window.name or global.main.
//    console.log(window.name); // my window's name is Sam?
    var correct = new Person; // person's name is actually stored in the person now.

})();

우리는 동물에 대한 하나의 기능을 건설 할 때 하드 코딩하는 대신 그 동물의 소리를 바라 보는 기능을 원합니다.

축복을 통해 패키지를 물체의 프로토 타입으로 사용할 수 있습니다. 이런 식으로 객체는 "패키지"가 "참조 된"것을 알고 있으며, 패키지의 함수는 "패키지 개체"의 생성자에서 만든 특정 인스턴스에 도달 할 수 있습니다.

package Animal;
sub new {
    my $packageRef = $_[0];
    my $name = $_[1]->{'name'};
    my $sound = $_[1]->{'sound'};

    my $this = {
        'name' => $name,
        'sound' => $sound
    };   

    bless($this, $packageRef);
    return $this;
}

# all animals use the same performSound to look up their sound.
sub performSound {
    my $this = shift;
    my $sound = $this->{'sound'};
    print $sound . "\n";
}

package main;
my $animal = Animal->new({
    'name' => 'Cat',
    'sound' => 'meow'
});
$animal->performSound();

요약/tl; dr:

Perl에는 "this", "class"또는 "new"가 없습니다. 패키지에 객체를 축복하면 해당 객체가 패키지에 대한 참조를 제공하며 패키지에서 함수를 호출 할 때는 인수가 1 슬롯으로 오프셋되며 첫 번째 인수 ($ _ [0] 또는 Shift)는 동일합니다. JavaScript의 "This". 차례로 JavaScript의 프로토 타입 모델을 다소 시뮬레이션 할 수 있습니다.

불행히도 런타임에 "새로운 클래스"를 만드는 것은 불가능합니다. 각 "클래스"가 자체 패키지를 갖기 위해 필요하기 때문에 자바 스크립트에서는 "새로운"키워드로 패키지가 전혀 필요하지 않습니다. 런타임에 패키지로 사용할 수 있도록 익명의 해시 맵을 구성하여 새로운 기능을 추가하고 즉시 함수를 제거 할 수 있습니다.

무스와 같은 표현력 에서이 한계를 연결하는 자체 방법을 만드는 일부 Perl 라이브러리가 있습니다.

왜 혼란?:

패키지 때문에. 우리의 직관은 우리에게 객체를 프로토 타입을 포함하는 해시 맵에 바인딩하도록 지시합니다. 이를 통해 JavaScript Can과 같이 런타임에 "패키지"를 만들 수 있습니다. Perl은 그러한 유연성이 없으며 (적어도 내장되지 않았으며, 그것을 발명하거나 다른 모듈에서 가져와야합니다), 런타임 표현성이 방해받습니다. "축복"이라고 부르는 것은 그다지 호의를 베풀지 않습니다.

우리가하고 싶은 일:

이와 같은 것이지만 프로토 타입 맵 재귀와의 결합을 가지고 있으며, 명시 적으로 그렇게하지 않고 프로토 타입에 암시 적으로 구속됩니다.

여기에 순진한 시도가 있습니다. 문제는 "호출"이 "무엇을 불렀는지"알지 못하므로 객체에 메소드가 있는지 확인하는 보편적 인 Perl 함수 "ObjectinVokemethod (Object, Method)"일 수도 있다는 것입니다. , 또는 그 프로토 타입에는 끝에 도달하고 찾을 때까지 (프로토 타입의 상속) 프로토 타입에 프로토 타입이 있습니다. Perl은 좋은 평가 마법을 가지고 있지만 나중에 할 수있는 일을 위해 떠날 것입니다.

어쨌든 여기에 아이디어가 있습니다.

(sub {

    my $Animal = (sub {
        my $AnimalPrototype = {
            'performSound' => sub {
                return $_[0]->{'sound'};
            }
        };

        my $call = sub {
            my $this = $_[0];
            my $proc = $_[1];

            if (exists $this->{$proc}) {
                return $this->{$proc}->();
            } else {
                return $this->{prototype}->{$proc}->($this, $proc);
            }
        };

        return sub {
            my $name = $_[0]->{name};
            my $sound = $_[0]->{sound};

            my $this = { 
                'this' => $this,
                'name' => $name,
                'sound' => $sound,
                'prototype' => $AnimalPrototype,
                'call' => $call                
            };
        };
    })->();

    my $animal = $Animal->({
        'name' => 'Jeff',
        'sound'=> 'bark'
    });
    print($animal->{call}($animal, 'performSound'));
})->();

어쨌든 누군가 가이 게시물이 유용하다는 것을 알기를 바랍니다.

나는이 생각을 따라 개발 객체 지향적 perl을 안내합니다.

축복 데이터 구조 참조를 클래스와 연관시킵니다. Perl이 상속 구조를 만드는 방법 (트리의 일종)을 감안할 때 객체 모델을 활용하여 구성을위한 객체를 만들기 쉽습니다.

이 연관성을 위해 우리는 객체라고 불렀으며, 발달하기 위해 항상 객체와 클래스 행동의 내부 상태가 분리되어 있음을 명심해야합니다. 또한 모든 데이터 참조가 패키지/클래스 동작을 사용하도록 축복/허용 할 수 있습니다. 패키지는 물체의 "정서적"상태를 이해할 수 있기 때문에.

예를 들어, 버그 객체가 축복받은 해시가 될 것이라고 확신 할 수 있다면 버그 :: print_me 메소드에서 누락 된 코드를 채울 수 있습니다.

 package Bug;
 sub print_me
 {
     my ($self) = @_;
     print "ID: $self->{id}\n";
     print "$self->{descr}\n";
     print "(Note: problem is fatal)\n" if $self->{type} eq "fatal";
 }

이제 Print_me 메소드가 버그 클래스에 축복 된 해시에 대한 참조를 통해 호출 될 때마다 $ Self Variable은 첫 번째 인수로 전달 된 참조를 추출한 다음 Print 문은 축복받은 해시의 다양한 항목에 액세스합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top