在我的问题的第一部分,我将提供一些背景信息作为社区服务.第二部分包含实际问题.
第一部分
假设我创建了以下别名:
alias ls='ls -r'
Run Code Online (Sandbox Code Playgroud)
我知道如何使用以下方式暂时unalias(即覆盖此别名),使用:
1)命令的完整路径名: /bin/ls
2)命令替换: $(which ls)
3)内置命令: command ls
4)双引号: "ls"
5)单引号: 'ls'
6)反斜杠字符: \ls
案例1是显而易见的,案例2只是一种变化.案例3中内置的命令旨在忽略shell函数,但显然它也可用于规避别名.最后,案例4和5与POSIX标准(2.3.1)一致:
"应检查一个被识别为简单命令的命令名字的结果字,以确定它是否是一个不带引号的有效别名."
"检查每个简单命令的第一个单词,如果没有引用,则检查它是否有别名."
第二部分
这是一个问题:为什么案例6(通过说法覆盖别名\ls)考虑引用这个词?为了与这个问题的风格保持一致,我正在寻找对"官方"文档的引用.
文档说反斜杠只转义后续字符,而不是单引号和双引号引用一系列字符. POSIX标准(2.2.1):
"未引用的反斜杠应保留以下字符的字面值,但<newline>除外"
"一个非引用的反斜杠'\'是Bash转义字符.它保留了下一个字符的字面值,除了换行符."
(顺便说一句,是不是"下一个角色"有点矫枉过正?)
一个可能的答案可能是这种情况并不那么特别:它类似于ANSI-C引用中的一些情况,例如\nnn.然而,这仍然是逸出的单个字符(八位字符,其值是八进制值NNN),而不是一个字符序列.
这个问题会很长,所以我先发制人道歉.
在Python中,我们可以在以下三种情况下使用*:
I.在定义一个我们想要用任意数量的参数调用的函数时,例如在这个例子中:
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
Run Code Online (Sandbox Code Playgroud)
在这种情况下,多余的位置参数被收集到元组中.
II.相反的情况是,当参数已经在列表或元组中时,我们希望为需要单独位置参数的函数调用解包它们,例如在本例中:
>>> range(3, 6) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]
Run Code Online (Sandbox Code Playgroud)
III.从Python 3开始,*也用于扩展列表或元组解包的上下文中,例如在这个示例中用于元组:
>>> a, *b, c = range(5)
>>> b
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
或列表:
>>> [a, *b, c] = range(5)
>>> …Run Code Online (Sandbox Code Playgroud) 在"C++ Primer"的第16章末尾,我遇到了以下代码(我删除了一堆行):
class Sales_item {
public:
// default constructor: unbound handle
Sales_item(): h() { }
private:
Handle<Item_base> h; // use-counted handle
};
Run Code Online (Sandbox Code Playgroud)
我的问题在于Sales_item(): h() { }线路.
为了完整起见,我还要引用我认为与我的问题相关的Handle类模板的部分(我想我不需要显示Item_base类):
template <class T> class Handle {
public:
// unbound handle
Handle(T *p = 0): ptr(p), use(new size_t(1)) { }
private:
T* ptr; // shared object
size_t *use; // count of how many Handles point to *ptr
};
Run Code Online (Sandbox Code Playgroud)
我原以为是这样的:
a)Sales_item(): h(0) { }这是作者在前几章中反复使用的惯例,或者
b)Handle<Item_base>()如果打算调用Handle类的默认构造函数.
相反,这本书有什么Sales_item(): h() { …
根据标准(§5.2.11),const_cast抛弃了cv-qualifiers(const或volatile).
这是一个简单的例子.首先,您声明两个函数采用指针和引用:
class Bar { ... };
void foo_ptr(Bar*);
void foo_ref(Bar&);
Run Code Online (Sandbox Code Playgroud)
然后你创建一个引用到const:
Bar b;
const Bar& cb = b;
Run Code Online (Sandbox Code Playgroud)
然后你可以使用适当的const_cast调用任一函数:
foo_ptr(const_cast<Bar*>(&cb));
foo_ref(const_cast<Bar&>(cb));
Run Code Online (Sandbox Code Playgroud)
这是我的问题:由于const_cast无法完成其他演员的设计,你投射的内容不是很明显吗?换句话说,为什么语言不允许我简单地说:
foo_ptr(const_cast<>(&cb));
foo_ref(const_cast<>(cb));
Run Code Online (Sandbox Code Playgroud)
我只能想到以下两个原因:
a)当我尝试做一些疯狂的事情时,编译器应该阻止我,例如:
foo_ptr(const_cast<int*>(&cb));
foo_ref(const_cast<int&>(cb));
Run Code Online (Sandbox Code Playgroud)
并强迫我明确说明我正在施放的类型,然后可以防止行为不端.我发现这个(假设的)解释很弱,因为如果语言偏好允许我写下错误只是为了让编译器纠正我,这将是奇怪的.
b)如果变量既是const又是volatile,则可能存在歧义.在这种情况下,编译器无法告诉我是否试图抛弃一个或另一个(或两者).
这是为什么,还是有其他原因?
在Mark Sobell的"Linux命令,编辑器和Shell编程实用指南"第二版中,他写道(第432页):
<&token复制输入文件描述符; >&复制输出文件描述符.
这似乎与同一页面上的另一个语句不一致:
使用以下格式打开或重定向文件描述符n作为文件描述符m的副本:
exec n <&m
并在同一页面上也有一个例子:
# File descriptor 3 duplicates standard input
# File descriptor 4 duplicates standard output
exec 3<&0 4<&1
Run Code Online (Sandbox Code Playgroud)
如果> &&重复输出文件描述符,那么我们不应该说
exec 4>&1
Run Code Online (Sandbox Code Playgroud)
复制标准输出?