Reputation: 6987
Is there any such thing as static variables in Ruby that would behave like they do in C functions?
Here's a quick example of what I mean. It prints "6\n7\n" to the console.
#include <stdio.h>
int test() {
static int a = 5;
a++;
return a;
}
int main() {
printf("%d\n", test());
printf("%d\n", test());
return 0;
}
Upvotes: 5
Views: 2576
Reputation: 7725
What I understand about this C code is that the static variable is initialized with a value (5
in this case), and its value is persisted across function calls.
In Ruby and languages with the same level of abstraction, this same thing is typically achieved either by using a variable that sits outside the scope of the function or by using an object to hold that variable.
def test()
@a ||= 5 # If not set, set it. We need to use an instance variable to persist the variable across calls.
@a += 1 # sum 1 and return it's value
end
def main()
puts test
puts test
0
end
Ruby's quirk is that you can use instance variables even outside of a class definition.
Upvotes: 6
Reputation: 1585
Use a variable in the singleton class (The static class itself)
class Single
def self.counter
if @count
@count+=1
else
@count = 5
end
end
end
In ruby, any class is an object which has only one instance. Therefore, you can create an instance variable on the class, and it will work as a "static" method ;)
Output:
ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-linux]
=> :counter
Single.counter
=> 5
Single.counter
=> 6
Single.counter
=> 7
To get this behaviour on the main scope, you can do:
module Countable
def counter
if @count
@count+=1
else
@count = 5
end
end
end
=> :counter
self.class.prepend Countable # this "adds" the method to the main object
=> Object
counter
=> 5
counter
=> 6
counter
=> 7
Upvotes: 1
Reputation: 168101
I think a standard way to do this is to use Fiber
.
f = Fiber.new do
a = 5
loop{Fiber.yield a += 1}
end
puts f.resume # => 6
puts f.resume # => 7
...
Upvotes: 0
Reputation: 15284
Scope your variable in a method and return lambda
def counter
count = 0
lambda{count = count+1}
end
test = counter
test[]
#=>1
test[]
#=>2
Upvotes: 3
Reputation: 38586
Similar to nicooga's answer but more self-contained:
def some_method
@var ||= 0
@var += 1
puts @var
end
Upvotes: 4
Reputation: 8293
You can use a global variable:
$a = 5
def test
$a += 1
end
p test #=> 6
p test #=> 7
Upvotes: 3