0Pricing
R Academy · 课时

运算符优先级与复杂表达式

了解求值顺序,并安全地编写复杂表达式

运算符优先级与复杂表达式 是 CoddyKit 上的免费 R Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。

什么是运算符优先级

运算符优先级决定表达式中各项运算的求值顺序。和数学规则一样,乘法会先于加法求值。R 遵循一套明确定义的优先级表。

# Precedence in action
result1 <- 2 + 3 * 4    # * before +
result2 <- (2 + 3) * 4  # parentheses override
cat('2 + 3 * 4 =', result1, '
')   # 14
cat('(2+3) * 4 =', result2, '
')   # 20

R 的优先级表(从高到低)

R 按照以下顺序计算运算符(优先级最高的在前):

  1. ^ — 乘方
  2. -(一元)— 取负
  3. : — 序列
  4. %%, %/%, %*%, %in% — 特殊中缀运算符
  5. *, / — 乘法、除法
  6. +, -(二元)— 加法、减法
  7. <, >, <=, >=, ==, != — 比较
  8. ! — NOT
  9. &, && — AND
  10. |, || — OR
  11. <-, = — 赋值
# Exponentiation before multiplication
cat('2 * 3 ^ 2 =', 2 * 3 ^ 2, '
')   # 2 * 9 = 18
cat('(2*3)^2 =', (2 * 3) ^ 2, '
')   # 6^2 = 36

# Unary minus applied after exponentiation
cat('-2 ^ 2 =', -2 ^ 2, '
')    # -(2^2) = -4
cat('(-2)^2 =', (-2) ^ 2, '
')  # 4

冒号运算符的优先级

: 序列运算符的优先级高于 + 和 -,这会导致初学者经常犯错:1:n+1 会被理解为 (1:n)+1,而不是 1:(n+1)。

n <- 5

# Common mistake: colon before addition
cat('1:n+1 =', 1:n + 1, '
')   # (1:5)+1 = 2 3 4 5 6
cat('1:(n+1) =', 1:(n + 1), '
') # 1:6 = 1 2 3 4 5 6

# These are DIFFERENT results!
# Always use parentheses when the upper bound involves arithmetic

特殊运算符的优先级

%%、%/% 和 %in% 等特殊运算符的优先级高于 + 和 -,但低于 ^。误解这一点会导致难以察觉的错误。

# %% has higher precedence than +
cat('10 + 7 %% 3 =', 10 + 7 %% 3, '
')   # 10 + (7%%3) = 10+1 = 11
cat('(10+7) %% 3 =', (10 + 7) %% 3, '
') # 17 %% 3 = 2

# %in% precedence
nums <- 1:5
cat('1 + 1 %in% nums =', 1 + 1 %in% nums, '
')  # (1+1) %in% nums? No! 1 + (1 %in% nums) = 2

先比较,后进行逻辑运算

比较运算符(<、>、== 等)会先于逻辑运算符(!、&、|)求值。因此,x > 0 & y < 10 无需额外的括号也能按预期运行。

x <- 5
y <- 8

# This works as intended: comparisons first, then &
cat('x > 0 & y < 10:', x > 0 & y < 10, '
')  # TRUE & TRUE = TRUE

# ! NOT has higher precedence than &
vec <- c(TRUE, FALSE, TRUE)
cat('!vec & TRUE:', !vec & TRUE, '
')  # (!vec) & TRUE, not !(vec & TRUE)
cat('!(vec & TRUE):', !(vec & TRUE), '
')

棘手的优先级错误 #1

一种常见错误是忘记 ! 的优先级低于比较运算符,也就是说,!x == y 会被理解为 (!x) == y,而不是 !(x == y)。

x <- 5
y <- 5

# BUG: meant to check 'x is not equal to y'
bug_result <- !x == y      # reads as (!x) == y
cat('!x == y (bug):', bug_result, '
')   # !5 means FALSE, FALSE==5 is FALSE

# CORRECT: use != or !(x == y)
cat('x != y:', x != y, '
')             # FALSE (correct)
cat('!(x == y):', !(x == y), '
')       # FALSE (correct)

棘手的优先级错误 #2

另一个容易忽略的错误是:-1:5 会创建序列 -1, 0, 1, 2, 3, 4, 5——一元减号只作用于 1,而不是整个范围。若要创建从负数开始的范围,请使用括号。

# Misleading: looks like range from -1 to 5 starting at negative
seq1 <- -1:5
cat('-1:5 =', seq1, '
')  # -1 0 1 2 3 4 5 (correct here)

# But -2^2 is a trap:
cat('-2^2 =', -2 ^ 2, '
')    # -4 (not 4)
cat('(-2)^2 =', (-2) ^ 2, '
') # 4

# Always parenthesise to be safe
cat('(-1):5 =', (-1):5, '
')   # same as -1:5 but explicit

使用括号提升可读性

即使严格来说不需要括号,使用括号也能让代码更易读、更不容易出错。不要依赖记忆完整的优先级表——请使用括号清楚地表达您的意图。

# Hard to read — requires knowing precedence
result_unclear <- 2 + 3 * 4 ^ 2 / 8 - 1

# Clear intent with parentheses
result_clear <- 2 + ((3 * (4 ^ 2)) / 8) - 1

cat('Unclear:', result_unclear, '
')
cat('Clear:  ', result_clear, '
')
cat('Same result?', result_unclear == result_clear, '
')

表达式中的赋值

赋值(<-)的优先级非常低,低于大多数运算符。这意味着您可以在一行中给任意复杂表达式的结果赋值,但也意味着表达式中的赋值可能表现得出乎意料。

# <- has very low precedence
# This assigns (3 + 4) to x, then evaluates (TRUE)
result <- x <- 3 + 4   # x gets 7, result gets 7
cat('x:', x, 'result:', result, '
')

# Be careful with == vs <- 
# x <- 5 is assignment
# x == 5 is comparison (always use == for testing)

实践:避免优先级错误

编写正确的复杂表达式时,可以采用以下实用策略:将长表达式拆分为带名称的中间步骤。这样也更容易调试,因为您可以检查每一步的结果。

# Complex formula: compound interest
principal <- 1000
rate <- 0.05
years <- 10

# Hard to verify in one line
bad <- principal * (1 + rate) ^ years

# Easier to verify step by step
growth_factor <- (1 + rate) ^ years
final_amount <- principal * growth_factor
cat('Growth factor:', round(growth_factor, 4), '
')
cat('Final amount: $', round(final_amount, 2), '
')

逻辑 AND/OR 的优先级

&(AND)的优先级高于 |(OR)。因此,A | B & C 会按 A | (B & C) 求值。混合使用 AND 和 OR 时,请务必使用括号,以避免难以察觉的逻辑错误。

A <- TRUE
B <- FALSE
C <- TRUE

# & before | — may surprise you
cat('A | B & C:', A | B & C, '
')     # A | (B & C) = TRUE | FALSE = TRUE
cat('(A|B) & C:', (A | B) & C, '
')   # TRUE & TRUE = TRUE

# Different with:
A2 <- FALSE
cat('A2 | B & C:', A2 | B & C, '
')   # FALSE | (FALSE & TRUE) = FALSE
cat('(A2|B) & C:', (A2 | B) & C, '
') # (FALSE|FALSE) & TRUE = FALSE

快速检查

-3 ^ 2 在 R 中的计算结果是什么?

回顾:运算符优先级

非常棒!以下是本课的要点:

  • 优先级顺序(从高到低):^、一元 -、:、%%/%/%*%%in%、*/、+-、比较运算符、!、&、|、赋值
  • -2^2 = -4,因为 ^ 的优先级高于一元减号;若要得到 4,请使用 (-2)^2
  • 1:n+1 表示 (1:n)+1;如果想得到更长的范围,请使用 1:(n+1)
  • & 的结合程度高于 |;混合使用 AND/OR 逻辑时请加括号
  • 不确定时,请使用括号明确表达意图并避免错误
# Golden rule: parentheses for clarity
n <- 4
# Intended: sequence 1 to n+1
cat('Wrong : 1:n+1  =', 1:n + 1, '
')
cat('Correct: 1:(n+1)=', 1:(n + 1), '
')

# Intended: -(2^2)
cat('Correct: -2^2 = -(2^2) =', -2 ^ 2, '
')

常见问题解答

「运算符优先级与复杂表达式」课时是免费的吗?

是的 — 「运算符优先级与复杂表达式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。

「运算符优先级与复杂表达式」这节课中我会学到什么?

了解求值顺序,并安全地编写复杂表达式 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 R Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「运算符优先级与复杂表达式」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 R Academy 课中编写并运行代码吗?

能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 算术与比较运算符
  2. 逻辑运算符与布尔逻辑
  3. 赋值与特殊运算符
  4. 运算符优先级与复杂表达式
← 返回 R Academy