สร้างวัตถุที่มีการเปลี่ยนแปลงสถานะในการมอบหมาย


31

ฉันคิดว่ามันแปลกมากที่ทับทิมนี้เป็นไปได้ (ฉันจะไม่พูดในทันที):

obj = #code redacted

print obj.state # Some value.

LValue = obj

print obj.state # Different value!

ความท้าทายของคุณคือการสร้างรหัสคร่าวๆของแบบฟอร์มนี้ สร้างวัตถุและกำหนดให้กับตัวแปร มันควรจะมีคุณสมบัติที่กำหนดไว้ (หรือวิธีการที่กำหนดขึ้น, idempotent) เหมือนstateด้านบน, การเปลี่ยนแปลงหลังจากที่วัตถุถูกกำหนดให้กับตัวระบุใหม่ ( LValueด้านบน), แม้ว่าคุณจะยังคงใช้ตัวระบุเก่า ( objด้านบน) เพื่ออ้างอิง

แก้ไขเพื่อเน้น : stateหรือสิ่งที่เทียบเท่าจะต้องเป็น idempotent ดังนั้นการสร้าง accessor ที่ปรับเปลี่ยนค่าหรือด้วยเหตุผลอื่นใดให้ผลลัพธ์ที่แตกต่างกันเมื่อเรียกหลาย ๆ ครั้งในแถวไม่ใช่โซลูชันที่ถูกต้อง หรือยิ่งกว่านั้นจะต้องมีการกำหนดที่เปลี่ยนแปลงสถานะ

ภาษาใด ๆ ที่ได้รับมอบหมายมีสิทธิ์แม้ว่าอาจมีบางภาษาที่ไม่มีวิธีการแก้ปัญหาที่ถูกกฎหมายอย่างสมบูรณ์ ฉันจะโพสต์คำตอบ Ruby ของฉันหากไม่มีใครได้รับหลังจากผ่านไปสองสามวันและยอมรับคำตอบที่ได้รับคะแนนสูงสุด


ต้องมีการเปลี่ยนLValue = objบรรทัดstateหรือไม่ (ฉันเพียงแค่จะทำให้ทรัพย์สินใน C # ที่เพิ่มขึ้นทุกครั้งที่คุณได้รับมัน)
ทิมเอส

2
ใช่นั่นคือสิ่งที่ฉันตั้งใจด้วยการพูดถึงวิธีการที่จำเป็นสำหรับ idempotent ฉันจะแก้ไขให้ชัดเจนยิ่งขึ้น
ชำนาญวิชาประวัติศาสตร์

โอเคขอบคุณ. ฉันจะต้องคัดค้านส่วนนั้น
Tim S.

4
จะคืนค่า refcount ของวัตถุหรือไม่
Nick T

การดัดแปลงวัตถุจะทำลายล้างหรือไม่? EmacsLisp: (setq a (list "val")) (setq b (nconc a "val2"))ตัวอย่างเช่น aสิ้นสุดการประเมิน("val" . "val2")ณ จุดนั้น
Jonathan Leech-Pepin

คำตอบ:


30

C ++

นี่เป็นเรื่องเล็กน้อยโดยใช้เครื่องมือที่เหมาะสม

#include <iostream>

using namespace std;

class Obj {
public:
   int state;

   Obj& operator= (Obj& foo) {
      foo.state++;
      this->state = foo.state - 2;
      return *this;
   }
};

int main() {
   Obj a, b, c, d;
   a.state = 3;
   b.state = 4;

   cout << a.state << " " << b.state << "\n";

   c = a;
   d = b;

   cout << a.state << " " << b.state << " " << c.state << " " << d.state << "\n";

   return 0;
}

เอาท์พุท:

3 4
4 5 2 3

12
ทันทีที่ฉันเห็นชื่อฉันรู้ว่ามีคนทำโอเปอเรเตอร์มากไป มันเป็นวิธีที่ชัดเจน มี upvote

17

PHP (debug build,> = 5.4)

เราใช้ refcount ของวัตถุในทะเยอทะยาน (ดังนั้นโดยการมอบหมาย refcount เพิ่มและการเปลี่ยนแปลงค่า)

class State {
    public function __get($arg) {
        ob_start();
        debug_zval_dump($this); // e.g. "object(State)#1 (0) refcount(6)"
        return ob_get_clean()[29];
    }
}

$obj = new State;
var_dump($obj->state);
$a = $obj;
var_dump($obj->state);

14

C #

สองตัวเลือกง่าย ๆ :

class Obj
{
    public int state;
    public static implicit operator int(Obj o)
    {
        return o.state++;
    }
}

static int LValueI;
static Obj LValueM { set { value.state++; } }
static void Main()
{
    var obj = new Obj { state = 1 };
    LValueI = obj;
    Console.WriteLine(obj.state); //2, caused by the implicit cast.

    LValueM = obj;
    Console.WriteLine(obj.state); //3, caused by the property setter.
    Console.ReadLine();
}

หรือเราสามารถเขียนลงในหน่วยความจำเดียวกันได้:

[StructLayoutAttribute(LayoutKind.Explicit)]
class Program
{
    [FieldOffset(0)]
    int state = 1;
    [FieldOffset(1)]
    int LValue;

    void Test()
    {
        var obj = this;

        Console.WriteLine(state);  //1
        LValue = state;
        Console.WriteLine(state);  //257
        Console.ReadLine();
    }
    static void Main() { new Program().Test(); }
}

12

TeX สั้นกว่าคำตอบอื่น ๆ มากที่นี่

\setbox0=\hbox{Hello world!} % Put stuff in the box 0.
\message{\the\wd0}           % Print the width of the box => non-zero
\setbox2=\box0               % Put the box instead in box 2.
\message{\the\wd0}           % Now box 0 is void, hence has zero width.

ในฐานะที่เป็นระบบเรียงพิมพ์ TeX มีประเภท "box" ซึ่งมีวัสดุเรียงพิมพ์ เนื่องจากกรณีการใช้งานที่พบบ่อยที่สุดคือการย้ายวัสดุนี้ไปรอบ ๆ แบ่งมัน ฯลฯ แทนที่จะทำสำเนาของมันกล่องจะถูกลบตามปกติเมื่อใช้ (หรือมากกว่านั้นตัวแปร "กล่อง" เป็นตัวชี้และมีเพียงหนึ่งตัวชี้ในเวลาที่สามารถชี้ ไปยังกล่องจริงในหน่วยความจำ) ไม่จำเป็นต้องใช้เวทมนตร์ใด ๆ


8

C ++ 11 (พวกคุณลืมเกี่ยวกับ unique_ptr / shared_ptr :-))

#include <iostream>
#include <memory>
using namespace std;
int main() {
    std::unique_ptr<int> u1(new int(0)), u2;
    std::shared_ptr<int> s1 = std::make_shared<int>(0), s2;
    std::cout<<u1.get()<<" "<<u2.get()<<" "<<std::endl;
    std::cout<<s1.use_count()<<" "<<s2.use_count()<<" "<<std::endl;
    u2 = std::move(u1);
    s2 = s1;
    std::cout<<u1.get()<<" "<<u2.get()<<" "<<std::endl;
    std::cout<<s1.use_count()<<" "<<s2.use_count()<<" "<<std::endl;
   return 0;
}

7

Fortran 03

นี่ค่อนข้างคล้ายกับคำตอบ D ของ Hugo แต่ซ่อนไว้อีกเล็กน้อย (ส่วนหนึ่งเพราะ # $% ^ รู้จัก Object Oriented Fortran)

module objects
   implicit none

   type ObjDef
      integer :: state
    contains
      procedure :: initObject
      procedure :: printObject
      procedure :: setNew
   end type
 contains
   subroutine initObject(this)
     class(ObjDef) :: this
     this%state = this%state + 1
   end subroutine initObject

   subroutine printObject(this)
     class(ObjDef) :: this
     print '(a,i0)',"this%state = ",this%state
   end subroutine printObject

   subroutine setNew(this,that)
     class(ObjDef) :: this,that
     that%state = this%state
   end subroutine setNew

end module objects

program objectChange
   use objects
   type(ObjDef) :: a,b

   call initObject(a)
   call printObject(a)
   call b%setNew(a)
   call printObject(a)
end program objectChange

ผลลัพธ์คือ

this%state = 1
this%state = 0

หากคุณสามารถคิดได้ว่าเกิดอะไรขึ้นโบนัสจะชี้ไปที่คุณ! ถ้าไม่:

เมื่อโทรขั้นตอนsetNewในรูปแบบcall b%setNew(a), bเป็นปริยายอาร์กิวเมนต์แรกไม่ได้ครั้งที่สอง


7

PowerShell

สิ่งนี้จะสร้างวัตถุที่มีstateคุณสมบัติเป็นชื่อของตัวแปรที่ชี้ไปที่วัตถุ

$a = @{}| Add-Member -MemberType:16 -PassThru state -Value {
        (gv|?{$this -eq $_.Value}|%{$_.Name}) -join ','} 

'Before: ' + $a.state
$b = $a
'After: ' + $a.state

เอาท์พุต

Before: a,this
After: a,b,this

หมายเหตุ:วิธีนี้ใช้ไม่ได้หากการมอบหมายนั้นเกิดขึ้นในขอบเขตลูก

'Before: ' + $a.state
&{$b = $a}
'After: ' + $a.state

เอาท์พุท

Before: a,this
After: a,this

Get-Variable ฉลาด!
mazzy

5

Perl 5

ต่อไปนี้เป็นวิธีหนึ่งใน Perl:

package Magic {
    sub new { bless {state => 1} }
    use overload '""' => sub { $_[0]{state}++ };
}
use feature 'say';

my $obj = new Magic;
say $obj->{state};
substr($_, 0) = $obj;
say $obj->{state};

ผลลัพธ์นี้:

1
2

คำอธิบาย:

นี้เป็นโปรแกรมที่ตรงไปตรงมาของการบรรทุกเกินพิกัด โดยเฉพาะฉันโอเวอร์โหลดตัวดำเนินการแปลงสตริง""ซึ่งถูกเรียกเมื่อวัตถุที่โอเวอร์โหลดถูกกำหนดให้substr()(ซึ่งใช่คือค่า lvalue ทางกฎหมายใน Perl)

นอกจากนี้ยังมีตัวแปรพิเศษมากมายใน Perl ซึ่งจะระบุสิ่งที่ได้รับมอบหมาย ตัวอย่างเช่นต่อไปนี้ใช้งานได้:

my $obj = new Magic;
say $obj->{state};
$0 = $obj;
say $obj->{state};

ทางเลือกการแก้ปัญหา

นี่คือวิธีอื่น:

package Magic {
    use Devel::Peek 'SvREFCNT';
    sub new { bless \my $foo }
    sub state { SvREFCNT ${$_[0]} }
}
use feature 'say';

my $obj = new Magic;
say $obj->state;
my $other = $obj;
say $obj->state;

นี่stateคือวิธี (เราสามารถทำให้มันเป็นคุณลักษณะที่มีการผูก / เกินพิกัด shenanigans แต่นั่นจะทำให้สิ่งต่าง ๆ ซับซ้อน) ที่นับจำนวนการอ้างอิงถึงวัตถุอย่างแท้จริง ดังนั้นไม่เหมือนในโซลูชันแรกคุณต้องกำหนดให้$objกับตัวแปรปกติที่สามารถเก็บการอ้างอิงวัตถุเพื่อทำการเปลี่ยนแปลงสถานะ


5

JavaScript

ตกลงดังนั้นฉันทำรุ่นที่สั้นกว่าซึ่งทำงานเป็น SSCCE แต่ไม่พยายามแยกวิเคราะห์ JavaScript อย่างถูกต้องอีกต่อไปดังนั้นการนับการอ้างอิงอาจไม่ทำงานเมื่อใส่สคริปต์ที่ซับซ้อนมากขึ้น

(function run () {
    var lineOne = getLine (1), a, b, x, y, z;
    var x = {
        get state () {
            var x=/([a-z]+)\s*=\s*([a-z]+)/,c;
            return 1 + Object.keys (c = run.toString ().split ('\n').slice (0,getLine (2)).filter (function (a) {return (x.test (a))}).reduce (function (a,b,c,d) {var r=b.match (x),t=r[2];while (a[t]){t=a[t]};a[r[1]]=t;return a}, {v:0})).reduce (function (a,b) {return (c[b]=="x"?1:0) + a},0)
        }
    };
    console.log (x.state);  //1
    console.log (x.state);  //1
    y = x;
    console.log (x.state);  //2
    z = y;
    console.log (x.state);  //3    
    a = z;
    b = a;
    console.log (x.state);  //5
    a = null;
    console.log (x.state);  //4
    b = null;
    console.log (x.state);  //3
})() //1 1 2 3 5 4 3 

function getLine(n) {
   try {
      to
   } catch (dat) {
      var stack = dat.stack.split('\n');
       for (var i = 0; i < stack.length; i++) {
           if (~stack[i].indexOf ('getLine')) break;          
       }
      return dat.stack.split ('\n')[i + ~~n].match (/:(\d+)/)[1] - ~~window.hasOwnProperty ('__commandLineAPI')
   }
}

2
สนใจที่จะอธิบายสิ่งที่คุณทำ?
Ryan

5
... นี่อะไรในโลก? O_o
Doorknob

@Doorknob getter ที่ส่งคืนผลลัพธ์การเรียกใช้ฟังก์ชันซึ่งนับความถี่ที่ identifiername ถูกอ้างถึงเป็น rval ในนิพจน์การมอบหมายภายในแหล่งที่มาที่กำหนดจนถึงบรรทัดที่กำหนดผ่านแหล่งฟังก์ชันที่ล้อมรอบและบรรทัด ทะเยอทะยานได้รับเรียกจากเป็นข้อโต้แย้ง ทุกอย่างอื่นเป็นโทเค็นเซอร์ที่ยุ่งวุ่นวาย --- ฉันไม่รู้ว่าจะเรียกมันยังไงดี ในคำอื่น ๆ กล่าวอีกนัยหนึ่ง: getter จะนับจำนวนการมอบหมายการอ้างอิงถึง x จนถึงบรรทัดที่ถูกเรียกจากส่วนที่เหลือนั้นเป็น tokenizer ที่ยังไม่เสร็จ
C5H8NNaO4

1
ยาวที่สุด ... และกว้างที่สุด!
Nicolas Barbulesco

1
@NicolasBarbulesco ฉันทำให้มันสั้นลง
C5H8NNaO4

4

หลาม

มันโกงนิดหน่อย แต่วิธีการ:

import gc
class A(object):
    @property
    def state(self):
        return len(gc.get_referrers(self))

a = A()
print a.state
b = {"x": a}
print a.state
a.y = a
print a.state
del a
print b["x"].state

4

C ++ 11

แม้ว่าสิ่งนี้สามารถขยายได้สำหรับภาษาอื่น ๆ ที่รองรับ destrucors โดยนัย / ชัดเจน

#include <iostream>
using namespace std;

class Foo {
    int *ptr;
public:
    Foo() {
        ptr = new int(0);
    }   
    int state() {
        return *ptr;
    }
    ~Foo() {
        (*ptr)++;
    }
};
int main() {
    Foo a, b;
    cout << a.state() << " " << b.state() << "\n";
    {
        Foo c, d;
        c = a;
        d = b;
    }
   cout << a.state() << " " << b.state()  << "\n";

   return 0;
}

ผู้ประกอบการที่ได้รับมอบหมายเริ่มต้นดำเนินการคัดลอกตื้น ดังนั้นวัตถุที่รับยังคงเป็นเจ้าของตัวชี้และการเปลี่ยนแปลงใด ๆ ที่ส่งผลกระทบต่อวัตถุต้นฉบับ


1
ใช่newไม่มีdeleteในรายการ แม้ว่าสำหรับงานนี้มันเป็นเรื่องที่ดีพอผมคิดว่า :)
Ruslan

ผลลัพธ์คืออะไร
Nicolas Barbulesco

1
จากสิ่งที่ฉันเข้าใจ (C ++ ที่อยู่ห่างไกล ... ), ที่นี่ได้รับมอบหมายไม่เปลี่ยนแปลงรัฐ มิฉะนั้นเลื่อนcoutบรรทัดขึ้นก่อน}และบอกว่าใช้งานได้หรือไม่ :-)
Nicolas Barbulesco

4

สกาล่า

การแปลงโดยนัยช่วยให้คุณทำสิ่งนี้ได้ในขณะที่กำหนดให้กับตัวแปรโลคัลปกติ:

import scala.language.implicitConversions

class Obj {
  var counter = 0
}

implicit def o2s(x: Obj): String = {
  x.counter += 1
  x.toString
}

val obj = new Obj
println(obj.counter)
val s: String = obj
println(obj.counter)

คุณสามารถทำให้สำเร็จด้วยประเภทที่อนุมานได้เช่นกัน:

var s = ""
s = obj

คุณยังสามารถใช้วิธี setter แบบกำหนดเองได้แม้ว่าจะต้องใช้ค่า L เป็นเขตข้อมูล:

object L {
  var _value = new Obj
  def value = _value
  def value_=(x: Obj): Unit = {
    _value = x
    x.counter += 1
  }
}

val obj = new Obj
println(obj.counter)
L.value = obj
println(obj.counter)

3

D

struct Obj {
    int state;

    void opAssign (ref Obj other) {
        ++other.state;
    }
}

void main () {
    import std.stdio;

    Obj obj, lvalue;
    writeln(obj);
    lvalue = obj;
    writeln(obj);
}

เอาท์พุท:

Obj(0)
Obj(1)

3

ทับทิม

ตามที่สัญญาไว้นี่คือคำตอบที่เป็นแรงบันดาลใจให้กับคำถาม

obj = Class.new { def self.state; to_s[/</] ? "Has not been assigned\n" : "Assigned to #{to_s}"; end }

print obj.state

LValue = obj

print obj.state

Class.newสร้างคลาสที่ไม่ระบุชื่อ การเรียกto_sคลาสที่ไม่ระบุชื่อจะให้การแทนค่าสตริงเริ่มต้นของวัตถุซึ่งมีลักษณะ#<Class:0x007fe3b38ed958>ดังนี้ อย่างไรก็ตามเมื่อคลาสได้รับการกำหนดให้เป็นค่าคงที่to_sจะกลายเป็นค่าคงที่ ใน Ruby ค่าคงที่คือตัวแปรที่ขึ้นต้นด้วยตัวอักษรตัวใหญ่ดังนั้นobjการอ้างอิงไปยังคลาสที่อนุญาตให้มันไม่ระบุชื่อ

รหัสของฉันล้อมรอบto_sด้วยstateเมธอดดังนั้นผลลัพธ์จะกลายเป็น

Has not been assigned
Assigned to LValue

แตกต่างมากที่สุดของการแก้ปัญหาที่นี่งานนี้เพียงครั้งเดียว: การกำหนดที่จะคงที่อื่นจะไม่เปลี่ยนแทนสายของตนและจะไม่กำหนดค่าใหม่เพื่อobjLValue


3

ในภาษาจาวา

ฉันคิดว่ามันเป็นไปไม่ได้ใน Java แต่…

ชั้นหลัก:

public class MyAppOfCats {

  public static void main(String[] args) {
    Cat tom = new Cat();
    System.out.println(tom.state()); 
    // Output : NOT-BEST-CAT
    Cat.bestCat = tom;
    System.out.println(tom.state());
    // Output : BEST-CAT
  }

}

คลาสแมว:

public class Cat {

  static Cat bestCat;

  public Cat() {
    super();
  }

  public String state() {
      return ((this == Cat.bestCat) ? "BEST-CAT" : "NOT-BEST-CAT");
  }

}

ฉันได้รับแรงบันดาลใจจาก @tbodt


1
ฉันรู้ว่ามันไม่ใช่ code-golf แต่คุณรู้ว่าคุณสามารถเอานวกรรมิกออกได้และมันก็ยังเหมือนเดิมใช่ไหม
David Conrad

2
นี่ไม่ใช่ "วัตถุที่มีการเปลี่ยนแปลงสถานะในการมอบหมาย" นี่คือคุณจัดการค่าระดับโลกแล้วพิมพ์บางสิ่งตามค่านั้น มันไม่แตกต่างจากนั้นพิมพ์Cat.x = 2 Cat.x
Chris Hayes

@Chris - สถานะวัตถุขึ้นอยู่กับ“ มูลค่าทั่วโลก” ดังนั้นสถานะของวัตถุจึงเปลี่ยนไปตามการมอบหมาย คำถามระบุว่า ;-) ว่ารัฐนั้นอาจเป็นวิธีการที่กำหนดขึ้นได้อย่างเด็ดขาด สถานะวิธีการของฉัน()เป็นวิธีการดังกล่าว
Nicolas Barbulesco

ไม่มีสถานะของวัตถุที่มีการเปลี่ยนแปลงในงานนี้โดยเฉพาะอย่างยิ่ง ถ้าฉันทำCat otherCat = tomรัฐจะไม่เปลี่ยนแปลงเลย ฉันมีเวลายากที่จะเชื่อว่าสิ่งนี้สอดคล้องกับตัวอักษรหรือวิญญาณของกฎ
Chris Hayes

@Chris - แน่นอนว่าวัตถุเปลี่ยนแปลงในการมอบหมายนี้! คำถามจะถามถึงวัตถุที่สถานะถูกเปลี่ยนโดยการมอบหมาย ไม่ใช่สำหรับวัตถุที่มีสถานะเปลี่ยนแปลงโดยการมอบหมายใด ๆ
Nicolas Barbulesco

3

C ++

พฤติกรรมนี้มีการระบุในมาตรฐานจริง (และนั่นเป็นสาเหตุที่เลิกใช้แล้ว)

#include<iostream>
#include<memory>
int main()
{
    std::auto_ptr<int> a(new int(0));
    std::cout<<a.get()<<'\n';
    std::auto_ptr<int> b = a;
    std::cout<<a.get()<<'\n';
}

เอาท์พุต

some address
0

กระบวนการที่ทำให้สิ่งนี้เป็นเช่นเดียวกับคำตอบของอภิสิทธิ์ แต่ไม่จำเป็นต้องมีstd::moveและเหมือนกับคำตอบของ marinus แต่ใช้คลาสมาตรฐานแทนที่จะกำหนดเอง

แก้ไข: ฉันกำลังเพิ่มคำอธิบายบางอย่าง ในผลลัพธ์ "ที่อยู่บางส่วน" จะเป็นค่าเลขฐานสิบหกสำหรับที่อยู่ของจำนวนเต็มที่จัดสรร std::auto_ptrปล่อยตัวชี้การจัดเก็บเมื่อกำหนดให้กับตัวอื่นauto_ptrและตั้งค่าตัวชี้ภายในเป็น 0 การเรียกget()ดึงการเข้าถึงตัวชี้การจัดเก็บ


ฉันสงสัยว่า "เอาท์พุท" ที่นี่ไม่ใช่ของจริง
Nicolas Barbulesco

คุณช่วยอธิบายสิ่งนี้ควรทำอย่างไร? โดยเฉพาะอย่างยิ่งวิธีการget()? ทำไมมันกลับเป็น 0 ในตอนท้าย
Nicolas Barbulesco

@Nicholas yep เอาต์พุตนี้ไม่ใช่เอาต์พุตจริง แต่เป็นเอาต์พุตทั่วไปมากขึ้น (ฉันยังไม่สามารถเข้าถึงคอมไพเลอร์ได้ดังนั้นฉันจึงไม่มีตัวอย่างของที่อยู่ที่ถูกต้องในเวลานั้น)
JKor

1
หืมนี่ไม่สามารถคอมไพล์ใน gcc 4.8
Michael Hampton

1
ฉันแก้ไขข้อผิดพลาดในการรวบรวม ยังมีคำเตือนถ้าคุณกำลังคอมไพล์สำหรับ c ++ 11 เพราะauto_ptrเลิกใช้แล้ว
JKor


2

Python 2.x

ฉันไม่สามารถหาวิธีที่เหมาะสมในการทำสิ่งนี้ได้

class State(object):
    def __init__(self):
        self.state = 0
    def __set__(self, obj, other):
        # Keep different references
        other.state += 1
        self.state += 2

class Program(object):
    obj, value = State(), State() # Create two State-objects
    def __init__(self):
        print "Before assignment:", self.obj.state, self.value.state # 0 0
        self.value = self.obj # Set value to obj (supposedly)
        print "After  assignment:", self.obj.state, self.value.state # 1 2
        self.value = self.obj
        print "2nd    assignment:", self.obj.state, self.value.state # 2 4

Program()

2

ชวา

โซลูชันอื่น ๆ ทั้งหมดใช้รูปแบบการดำเนินการมากเกินไปของภาษา Java ไม่มีผู้ให้บริการโหลดมากเกินไปดังนั้นฉันคิดว่าฉันติดอยู่ แต่ฉันมากับบางสิ่งบางอย่าง

นี่คือคลาสหลัก:

public class Program {
    public static void main(String[] args) {
        Thing thing = new Thing(0);
        System.out.println(thing.getState());
        Thing.otherThing = thing;
        Thread.sleep(1);
        System.out.println(thing.getState());
    }
}

มีเส้นที่น่าสงสัยอยู่สองสามข้อ แต่พวกเขาจะไม่ทำอะไรเลยถ้าThingชั้นเรียนปกติ มันไม่ใช่:

public class Thing {
    private int state;

    public Thing(int state) {
        this.state = state;
    }

    public int getState() {
        return state;
    }

    // Please do your best to ignore the rest of this class.
    public static volatile Thing otherThing;
    static {
        Thread t = new Thread() {
            public void run() {
                Thing t = otherThing;
                while (true)
                    if (t != otherThing) {
                        t = otherThing;
                        t.state++;
                    }
            }
        };
        t.setDaemon(true);
        t.start();
    }
}

ไม่รับประกันว่าจะทำงานได้เนื่องจากเธรด แต่ฉันทดสอบบน JDK 1.8u5 และทำงานได้ที่นั่น



@KyleKanos กำจัด chic ของ unicode ทั้งหมด> U + 00FF
tbodt

1

เสียงกระเพื่อมสามัญ

ฉันกำหนดสถานะเป็นจำนวนของตัวแปรพิเศษที่ผูกไว้กับเวกเตอร์ ดังนั้นการกำหนดตัวแปรพิเศษจะเปลี่ยนสถานะ

(defgeneric state (object)
  (:documentation "Get the state of this object."))

(defmethod state ((object vector))
  ;; The state of a vector is the number of symbols bound to it.
  (let ((count 0))
    ;; Iterate each SYM, return COUNT.
    (do-all-symbols (sym count)
      ;; When SYM is bound to this vector, increment COUNT.
      (when (and (boundp sym) (eq (symbol-value sym) object))
    (incf count)))))

(defparameter *a* #(this is a vector))
(defparameter *b* nil)
(defparameter *c* nil)

(print (state *a*))
(setf *b* *a*)
(print (state *a*))
(print (state *a*))
(setf *c* *a*)
(print (state *a*))

เอาท์พุท:

1 
2 
2 
3 

ใช้งานได้กับการมอบหมายให้กับตัวแปรพิเศษเท่านั้นไม่ใช่กับตัวแปรศัพท์หรือไปยังสล็อตภายในวัตถุ

ระวังdo-all-symbolsลักษณะที่ปรากฏในแพ็คเกจทั้งหมดดังนั้นจึงขาดตัวแปรที่ไม่มีแพ็คเกจ อาจนับสัญลักษณ์ที่มีอยู่ในแพ็คเกจมากกว่าหนึ่งแพ็คเกจ (เมื่อแพ็คเกจหนึ่งนำเข้าสัญลักษณ์จากแพ็คเกจอื่น)

ทับทิม

ทับทิมเกือบจะเหมือนกัน แต่ฉันกำหนดสถานะเป็นจำนวนค่าคงที่ที่อ้างอิงถึงอาร์เรย์

class Array
  # Get the state of this object.
  def state
    # The state of an array is the number of constants in modules
    # where the constants refer to this array.
    ObjectSpace.each_object(Module).inject(0) {|count, mod|
      count + mod.constants(false).count {|sym|
        begin
          mod.const_get(sym, false).equal?(self)
        rescue NameError
          false
        end
      }
    }
  end
end

A = %i[this is an array]
puts A.state
B = A
puts A.state
puts A.state
C = A
puts A.state

เอาท์พุท:

state-assign.rb:9:in `const_get': Use RbConfig instead of obsolete and deprecated Config.
1
2
2
3

นี่เป็นลักษณะทั่วไปของคำตอบของฮิสโทแคตต่อวัตถุทับทิมที่ไม่ใช่คลาสหรือโมดูล คำเตือนปรากฏขึ้นเนื่องจากการกำหนดค่าคงที่อัตโนมัติโหลดโค้ดบางอย่างที่ทำให้เกิดคำเตือน


0

C ++

ผลลัพธ์อาจแตกต่างกันในแพลตฟอร์มที่แตกต่างกัน การทดสอบบนideone

#include <iostream>
#include <cassert>
// File format: [ciiiiciiii...] a char (1 byte) followed by its state (4 bytes)
// Each group takes 5 bytes
char Buffer[30]; // 5*6, six groups

struct Group {
    char c;
    int state;
};

int main(void) {
    assert(sizeof(char) == 1);
    assert(sizeof(int) == 4);

    Group& first_group = *(Group*)(&Buffer[0]); // Group 1 is at 0
    Group& second_group = *(Group*)(&Buffer[5]); // Group 2 is at 5

    first_group.c = '2';
    first_group.state = 1234;

    std::cout << first_group.state << std::endl;

    second_group = first_group;

    std::cout << first_group.state << std::endl;

    return 0;
}

เอาท์พุท:

1234
13010

0

C #

class A
{
    public int N { get; set; }
    public override string ToString() { return N.ToString(); }
}
class B
{
    public int N { get; set; }
    public override string ToString() { return N.ToString(); }
    public static implicit operator A(B b) { b.N = -b.N; return new A { N = b.N }; }
}
public static void Test()
{
    A a = new A { N = 1 };
    B b = new B { N = 2 };
    Console.WriteLine("a is {0}, b is {1}", a, b);
    Console.WriteLine("a is {0}, b is {1}", a, b);
    a = b;
    Console.WriteLine("a is {0}, b is {1}", a, b);
    Console.WriteLine("a is {0}, b is {1}", a, b);
}

เอาท์พุท:

a is 1, b is 2
a is 1, b is 2
a is -2, b is -2
a is -2, b is -2

สิ่งนี้ทำอะไร นี่มันบรรทุกเกินพิกัด=หรือไม่?
Nicolas Barbulesco

@ Nicolas ไม่ตรง มันเป็นเวลาที่หล่อจาก a Bถึง an Aเพราะมันimplicit operator A(B b)มีผลข้างเคียง
ClickRick
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.