在前几期里,我们了解了static关键字在特定上下文中的含义。
今天我们看一看另一个环境。我们可以在局部作用域中使用 static 来声明一个变量。
这种情况和我们之前看到的两种static有点不同。这次的局部静态 Local static 有更多的含义。
声明一个变量,我们需要考虑两种情况:变量的生命周期 和 变量的作用域。
生命周期指的是变量实际存在的时间。换句话说,在它被删除之前,它会在我们的内存中存在多久。而变量的作用域是指我们可以访问变量的范围。
所以如果在一个函数内部声明一个变量,我们不能在其它函数中访问它。我们声明的变量对于声明的函数是局部的。
局部静态
局部 local static 变量允许我们声明一个变量,它的生命周期基本上相当于整个程序的生命周期,然而它的作用范围却被限制在这个函数内。
在任何作用域中声明它都可以,这个和函数没有关系,刚才我只是用函数举了一个例子,它并不仅仅局限在函数内部,也可以在 if 语句中,可以在任何位置。
这就是为什么函数作用域中的 static 和类作用域中的 static之间没有太大区别的原因,因为生命周期实际是相同的。唯一的区别是在类作用域中,类中的任何东西都可以访问它(这个静态变量)。
如果你在函数作用域中声明一个静态变量,它将是那个函数的局部变量。对类来说也是局部变量。
让我们来看一些例子。
我创建了一个函数。在其中声明一些静态变量。
这意味着当我第一次调用函数时,这个变量将被初始化为 0。然后所有对函数的后续调用实际上不会创建另一个全新的变量。
检验的方法很简单。
可以先把static删掉。每次调用函数都增加 i 的值,然后打印它的值。
每一次调用这个函数时 i 都会被设置为 0。然后增加 1,通过调用函数来进行测试。
你可以看到1被打印了5次。
我们恢复 static。
其实这个时候非常类似于我把最初的声明移到函数外面。
我们现在运行代码。 i 开始的时候是0,然后累加 5 次。
所以你会得到这样的结果。
这样的写法没有任何问题。但是我们可以在任何地方访问 i。比如你可以在 function 函数调用之间让 i 等于 10。这可以极大的改变你的程序所做的事情。
所以如果你想要这样做,但又不希望让每个人都能访问这个变量。你可以在局部作用域下声明成 static。像我一开始写的程序那样。
这意味着我们第一次运行这个函数时,首先创建变量。并设为 0,后面它们都是指原来的变量。
运行这个程序,我们会得到和上面一样的结果。
但是之前那个变量 i 在全局范围内是可见的,虽然它是函数的局部变量。
有些人不赞成使用这种方法,我不理解其中的原因,我不认为这有什么问题。
它确实有它的用处。上面的例子就是其中之一。
其他的实现方式
你可以使用其它方法实现完全相同的行为。比如你可以用类来实现。
我们再来看下一个例子。
这里有一个单例类。——单例类是只存在一个实例的类。
如果我想创建这个单例类,而不使用静态局部作用域,我就需要创建静态的单例实例。我们设置了一个指针。如果你想返回一个引用,我必须有一个返回 Singleton& 的 Get 函数,它是静态的,然后返回我的的实例。
当然,我需要声明这个实例,并把它默认设为空指针。这样我就有了一个单例类。
我可以调用 Singleton::Get,然后对它做任何我想做的事情。
比如我设置了一个方法 hello,在下面调用,我们就得到了一个可以使用的一个类实例。
虽然可以,但是你不一定要非要这样做。
另一种方式就是你可以使用我们的新学的内容。local Static,代码可能是这个样子。
我们得到了完全相同的行为。可以看到一切都保持不变。它可以成功运行,没有崩溃。
现在你可以看到我们的代码干净多了。
当然如果上面的例子没有 static 关键字,那么这个实例会在栈上面创建。代码运行到花括号的时候,函数作用域结束时就会被销毁。这是一个严重的错误,特别是还来引用它,如果只是复制了它,那不会有问题。但是我们返回的是一个对它的引用。这个就会出大问题。
通过添加静态,将它的生命周期延长到永远。我们第一次调用 get。它实际上会构造一个单例实例。接下来的时间。它只会返回这个已经存在的实例。
最后的话
这是一个很好的例子。当你想这样用的时候,不一定非要用单例类。可以通过替换掉初始化函数来实现。例如,你可能需要在程序中的某处调用一个静态初始化函数来创建所有对象。你就可以使用静态 get 方法之类的东西,在很多情况下用它来简化代码。
你可以看到它有很多用途,真的很好用,所以请多多练习使用它。
以上是我使用过程中的一些想法,大家有什么别的看法可以发在评论区哈。
下期再见。