Com*_*hip 140 language-agnostic bitwise-operators negation
所以这更像是一个理论问题.C++和直接基于它的语言(in)(Java,C#,PHP)具有快捷运算符,用于将大多数二元运算符的结果赋值给第一个操作数,例如
a += 3; // for a = a + 3
a *= 3; // for a = a * 3;
a <<= 3; // for a = a << 3;
Run Code Online (Sandbox Code Playgroud)
但是当我想切换一个布尔表达式时,我总会发现自己写的东西就像
a = !a;
Run Code Online (Sandbox Code Playgroud)
这a是一个很长的表达式,这会很烦人.
this.dataSource.trackedObject.currentValue.booleanFlag =
!this.dataSource.trackedObject.currentValue.booleanFlag;
Run Code Online (Sandbox Code Playgroud)
(是的,德米特定律,我知道).
所以我想知道,是否有任何语言都使用一元布尔切换运算符,这将允许我缩写a = !a而不重复表达式a,例如
!=a;
// or
a!!;
Run Code Online (Sandbox Code Playgroud)
让我们假设我们的语言有一个适当的布尔类型(比如bool在C++中)并且a属于那种类型(所以没有C风格int a = TRUE).
如果你能找到一个文档化的源代码,我也有兴趣了解一下,例如C++设计者是否考虑在bool成为内置类型时添加类似的运算符,如果是这样,为什么他们决定反对它.
(注意:我知道有些人认为作业不应该使用
=,++并且+=不是有用的操作员,而是设计缺陷;让我们假设我对他们感到高兴,并专注于为什么他们不会扩展到bool).
dfr*_*fri 143
...这将允许我缩写
a = !a而不重复表达式a...
这种方法实际上并不是一个纯粹的"变异翻转"操作符,但确实符合上述标准; 表达式的右侧不涉及变量本身.
任何具有布尔XOR赋值的语言(例如^=)都允许翻转变量的当前值,例如a,通过XOR赋值来true:
// type of a is bool
a ^= true; // if a was false, it is now true,
// if a was true, it is now false
Run Code Online (Sandbox Code Playgroud)
正如@cmaster在下面的评论中所指出的,上面假设a是类型的bool,而不是例如整数或指针.如果a实际上是其他东西(例如,某些非bool评估为"真实"或"虚假"的值,而某些表示不是0b1或者0b0分别表示),则上述内容不成立.
举一个具体的例子,Java是一种语言,它定义明确,不受任何静默转换的影响.引用@ Boann的评论如下:
在Java中,
^并^=已明确定义行为布尔和整数(15.22.2.布尔逻辑运算符&,^和|),其中无论是运营商的双方必须是布尔值,或双方必须是整数.这些类型之间没有静默转换.因此,如果a声明为整数,则不会出现静默故障,而是出现编译错误.因此a ^= true;在Java中安全且定义良好.
toggle()自Swift 4.2起,以下演进提案已被接受并实施:
这toggle()为BoolSwift中的类型添加了一个本机函数.
toggle()切换布尔变量的值.
宣言
Run Code Online (Sandbox Code Playgroud)mutating func toggle()讨论
使用此方法可从切换一个布尔值
true来false或false到true.Run Code Online (Sandbox Code Playgroud)var bools = [true, false] bools[0].toggle() // bools == [false, false]
这本身不是运算符,但允许使用语言本机方法进行布尔切换.
Ric*_*ges 43
在c ++中,可以提交重新定义运算符含义的Cardinal Sin.考虑到这一点,以及一点点ADL,我们需要做的就是在我们的用户群上释放混乱是这样的:
#include <iostream>
namespace notstd
{
// define a flag type
struct invert_flag { };
// make it available in all translation units at zero cost
static constexpr auto invert = invert_flag{};
// for any T, (T << invert) ~= (T = !T)
template<class T>
constexpr T& operator<<(T& x, invert_flag)
{
x = !x;
return x;
}
}
int main()
{
// unleash Hell
using notstd::invert;
int a = 6;
std::cout << a << std::endl;
// let confusion reign amongst our hapless maintainers
a << invert;
std::cout << a << std::endl;
a << invert;
std::cout << a << std::endl;
auto b = false;
std::cout << b << std::endl;
b << invert;
std::cout << b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
预期产量:
6
0
1
0
1
Run Code Online (Sandbox Code Playgroud)
DrS*_*don 37
只要我们包括汇编语言......
INVERT 对于按位补码.
0= 对于逻辑(真/假)补充.
sup*_*cat 31
bool减小C99 会产生预期的效果,因为会增加或减少bit某些微型微控制器方言所支持的类型(从我观察到的那样,将位视为单位宽的位域,因此所有偶数都被截断为0并且所有奇数到1).我不会特别推荐这样的用法,部分是因为我不是bool类型语义的忠实粉丝[恕我直言,该类型应该指定一个bool除了0或1以外的任何值存储可能在读取时表现得好像它包含一个Unspecified(不一定一致)的整数值; 如果一个程序试图存储一个不知道为0或1的整数值,它应该!!首先使用它].
Adr*_*ian 31
汇编语言
NOT eax
Run Code Online (Sandbox Code Playgroud)
请参阅https://www.tutorialspoint.com/assembly_programming/assembly_logical_instructions.htm
pax*_*blo 28
我假设你不会选择一种完全基于此的语言:-)无论如何,你可以用C++这样做:
inline void makenot(bool &b) { b = !b; }
Run Code Online (Sandbox Code Playgroud)
请参阅以下完整程序,例如:
#include <iostream>
inline void makenot(bool &b) { b = !b; }
inline void outBool(bool b) { std::cout << (b ? "true" : "false") << '\n'; }
int main() {
bool this_dataSource_trackedObject_currentValue_booleanFlag = false;
outBool(this_dataSource_trackedObject_currentValue_booleanFlag);
makenot(this_dataSource_trackedObject_currentValue_booleanFlag);
outBool(this_dataSource_trackedObject_currentValue_booleanFlag);
makenot(this_dataSource_trackedObject_currentValue_booleanFlag);
outBool(this_dataSource_trackedObject_currentValue_booleanFlag);
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样输出:
false
true
false
Run Code Online (Sandbox Code Playgroud)
Way*_*rad 22
PostScript是一种串联的,面向堆栈的语言,如Forth,它具有一元切换,而不是.在不操作切换堆栈顶部的值.例如,
true % push true onto the stack
not % invert the top of stack
% the top of stack is now false
Run Code Online (Sandbox Code Playgroud)
请参见" PostScript语言参考手册"(pdf).458.
Reg*_*lue 21
Visual Basic.Net通过扩展方法支持此功能.
像这样定义扩展方法:
<Extension>
Public Sub Flip(ByRef someBool As Boolean)
someBool = Not someBool
End Sub
Run Code Online (Sandbox Code Playgroud)
然后像这样调用它:
Dim someVariable As Boolean
someVariable = True
someVariable.Flip
Run Code Online (Sandbox Code Playgroud)
所以,你原来的例子看起来像:
me.DataSource.TrackedObject.CurrentValue.BooleanFlag.Flip
Run Code Online (Sandbox Code Playgroud)
Lau*_*nen 14
从纯粹的理论角度来看,这个问题确实很有意思.抛开一元,变异的布尔切换操作符是否有用,或者为什么许多语言选择不提供一个,我冒险尝试查看它是否确实存在.
TL; DR显然没有,但Swift允许你实现一个.如果你只想看看它是如何完成的,你可以滚动到这个答案的底部.
在(快速)搜索各种语言的功能之后,我可以放心地说,没有任何语言将此运算符实现为严格的变异就地操作(如果找到的话,请纠正我).接下来的事情就是看看是否有可以让你构建一种语言的语言.这需要两件事:
由于不支持这些要求中的任何一个或两个,将立即排除许多语言.Java for one不允许运算符重载(或自定义运算符),此外,所有基本类型都按值传递.Go不支持运算符重载(除了hacks).Rust仅允许运算符重载自定义类型.你几乎可以在Scala中实现这一点,让你使用非常有创意的命名函数并省略括号,但遗憾的是没有传递引用.Fortran非常接近,它允许自定义运算符,但特别禁止它们具有inout参数(在正常函数和子例程中允许).
然而,至少有一种语言可以包含所有必要的方框:Swift.虽然有些人已经链接到即将发布的.toggle()成员函数,但您也可以编写自己的运算符,它确实支持inout参数.瞧,看哪:
prefix operator ^
prefix func ^ (b: inout Bool) {
b = !b
}
var foo = true
print(foo)
// true
^foo
print(foo)
// false
Run Code Online (Sandbox Code Playgroud)
Fre*_*ios 14
在Rust中,您可以创建自己的特征来扩展实现Not特征的类型:
use std::ops::Not;
use std::mem::replace;
trait Flip {
fn flip(&mut self);
}
impl<T> Flip for T
where
T: Not<Output = T> + Default,
{
fn flip(&mut self) {
*self = replace(self, Default::default()).not();
}
}
#[test]
fn it_works() {
let mut b = true;
b.flip();
assert_eq!(b, false);
}
Run Code Online (Sandbox Code Playgroud)
您也可以^= true按照建议使用,在Rust的情况下,没有可能的问题,因为false它不是像C或C++中那样的"伪装"整数:
fn main() {
let mut b = true;
b ^= true;
assert_eq!(b, false);
let mut b = false;
b ^= true;
assert_eq!(b, true);
}
Run Code Online (Sandbox Code Playgroud)
Python支持这样的功能,如果变量与运算符具有bool类型(True或False)exclusive or (^=):
a = False
a ^= True
print(a) # --> True
a ^= True
print(a) # --> False
Run Code Online (Sandbox Code Playgroud)