1

In kotlin and C#, you can assign a variable, or else if the value is nil, you can throw an exception using the ?: and ?? operators.

For example, in C#:

var targetUrl = GetA() ?? throw new Exception("Missing A");
// alt
var targetUrl = GetA() ?? GetB() ?? throw new Exception("Missing A or B");

Is this possible in ruby? If so, how?

Basically, what I want to do is this

target_url = @maybe_a || @maybe_b || raise "either a or b must be assigned"

I'm aware I can do this

target_url = @maybe_a || @maybe_b
raise "either a or b must be assigned" unless target_url

but I'd like to do it in a single line if possible

4

4 回答 4

2

基本上,我想做的是这个

target_url = @maybe_a || @maybe_b || raise "either a or b must be assigned"

您必须添加括号才能raise使您的代码正常工作:

x = a || b || raise("either a or b must be assigned")

or使用控制流运算符而不是:会“更正确” ||(这使得括号是可选的)

x = a || b or raise "either a or b must be assigned"

这是 Perl 的“做这个或死”的成语,我认为它是干净整洁的。它强调了一个事实,即raise不提供结果x——它只是因为它的副作用而被调用。

但是,有些人认为or/and令人困惑,根本不应该使用。(参见ruby​​style.guide/#no-and-or-or

Rails 大量使用的模式是有两种方法,没有一种方法!不提供错误处理:

def a_or_b
  @maybe_a || @maybe_b
end

和其中一个!

def a_or_b!
  a_or_b || raise("either a or b must be assigned")
end

然后通过以下方式调用它:

target_url = a_or_b!
于 2021-02-23T08:25:45.200 回答
1

使用运算符优先级

另一种通过极少的代码更改来完成您想要的操作的方法是使用低优先级 or运算符,它的优先级低于||=。例如:

# This is closest to what you want, but violates many style guides.
target_url = @maybe_a || @maybe_b or raise "either a or b must be assigned"

您还可以在不更改其工作方式的情况下包装逻辑行,例如:

# Same code as above, but wrapped for line length
# and to clarify & separate its expressions.
target_url = @maybe_a || @maybe_b or
  raise "either a or b must be assigned"

无论哪种方式,代码都会按预期引发 RuntimeError 异常。由于优先规则,不需要括号。

请注意,许多类似这样的样式指南会告诉您完全避免使用or运算符,或者仅将其用于流量控制,因为它通常是导致难以一目了然的细微优先级错误的原因。话虽如此,包装版本实际上只是我的另一个答案的反转变体,并且在不使用括号的情况下很容易在视觉上区分,特别是在启用语法突出显示的情况下。您的里程和风格指南的严格程度肯定会有所不同。

于 2021-02-23T04:50:40.050 回答
1

你可以用括号解决它:

(target_url = @maybe_a || @maybe_b) || raise("either a or b must be assigned")
于 2021-02-23T02:37:22.120 回答
0

使用带有赋值表达式的后缀条件

因为 Ruby 中的大多数内容都计算为表达式,所以您可以将其作为单个逻辑行来执行,方法unless是使用后缀条件,后跟赋值表达式。我选择将线换行以适应合理的线长,但如果您真的想要“单线”,请随意将其设为单线。例如:

raise "either a or b must be assigned" unless
  target_url = @maybe_a || @maybe_b

如您所料,这将正确引发 RuntimeError。

自动激活

请注意,这种特殊方法将自动激活@maybe_a并分配nil给它。如果@maybe_a评估为假,它也会对@maybe_b执行相同的操作。虽然很方便,但如果您依赖定义,自动激活可能会在以后绊倒您?识别代码中其他地方的未定义变量。因此,这个习语的优缺点将取决于您更广泛的意图,但它肯定会在原始问题的范围内完成工作。

于 2021-02-23T03:45:35.113 回答